ich versuche in mein erstes kleines JavaFX Programm einen ProgressBar einzubauen (ist gelungen…) den ich in einem eigenen Thread “hochzählen” lassen will.
Aktuell läuft eine while Bedingung mit System.out.prinln… Ausgabe zum Testen, aber der ProgressBar läuft nicht mit sondern aktualisiert sich erst wenn die While Bedingung beendet wurde…
Ich habe schon X Versuche unternommen und mir “einen Wolf gegoogelt” aber ich komm nicht drauf…
Ich habe jetzt eine eigene Klasse (ProgressBarClass) gemacht die ich dann in einer anderen aufrufe:
import demo.ProfileController;
import static demo.ProfileController.testBar;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.scene.control.ProgressBar;
public class ProgressBarClass extends Thread {
public static void main(String[] args) {
// ProgressBarClass t = new ProgressBarClass();
// t.start();
Task task = new Task<Void>() {
// Platform.runLater(new Runnable() {
@Override
public void run() {
double progress = 250.0;
double count = 249.0;
while (progress != 100) {
testBar.setProgress(((progress - count) / count) * -1);
progress--;
try {
Thread.sleep(10);
} catch (InterruptedException ex) {
Logger.getLogger(ProfileController.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println(progress);
}
}
//}) ;
@Override
protected Void call() throws Exception {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
};
ProgressBar testBar = new ProgressBar();
testBar.progressProperty().bind(task.progressProperty());
new Thread(task).run();
}
}
Im ProfilController habe ich einen Button (csvTabelleAnzeigen). Hier soll auch der ProgressBar (zum Testen) durchlaufen…
.
.
.
public void csvTabelleAnzeigen(ActionEvent event) throws FileNotFoundException, IOException, Exception {
String[] args = null;
Stage stageCSVTabelleAnzeigen = new Stage();
ShowCSVInTable tw = new ShowCSVInTable();
tw.start(stageCSVTabelleAnzeigen);
//Thread für eigenständiges Starten des ProgressBars!!!
schreiben.ProgressBarClass.main(args);
}
.
.
.
leider weiß ich nicht mehr weiter, ich probiere schon seit Stunden etwas zu finden das Funktioniert… :wut:
dessen Aufbau könntest du dir doch zumindest grundsätzlich anschauen,
wobei du ja auch schon weit gekommen bist, zu Thread und Task:
die Schleife muss nebenläufig arbeiten, damit der GUI-Thread zeichnen kann, statt die Schleife zu bearbeiten
der nächste Schritt wäre dann gewesen, sich zu Thread etwas besser zu informieren,
oder Verwendung von javafx.concurrent.Task, was ich persönlich wie ganz JavaFX nicht kenne, da sage ich also nichts zu,
aber zu Thread ist nun ganz grundsätzlich zu wissen: mit start()-Aufruf starten! dann gibts intern tatsächlich einen Ausführungs-Thread, der run() abarbeitet,
wenn du nur run() aufrufst, ist das eine ganz normale Methode,
ein Object der Klasse Thread ist für sich auch keine Magie, einfach nur ein Objekt
also start(), dann geht es vielleicht schon
grundsätzlich etwas aufpassen, auch im Auskommentier-Wirrwarr:
wenn du new Thread(task) anlegst, dann braucht die Klasse ProgressBarClass nicht selber auch von Thread erben
Meiner ersten Sichtung nach sollte alles in call() stattfinden und du solltest die Methoden updateProgress() verwenden. Die rechnet sogar selbst den Prozentwert aus
die run-Methode von Task zu überschreiben ist sicher nicht vorgesehen,
dann kann man auch gleich ein Runnable nehmen,
aber ein einfacher Thread, einfach nur nebenläufig, geht für den Anfang ja auch,
schön dass im Link auch thread.start() aufgeführt ist
xception in thread "Thread-4" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-4
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:237)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:397)
at javafx.scene.Parent$1.onProposedChange(Parent.java:245)
at com.sun.javafx.collections.VetoableObservableList.setAll(VetoableObservableList.java:90)
at com.sun.javafx.collections.ObservableListWrapper.setAll(ObservableListWrapper.java:314)
at com.sun.javafx.scene.control.skin.ProgressBarSkin.initialize(ProgressBarSkin.java:289)
at com.sun.javafx.scene.control.skin.ProgressBarSkin.access$400(ProgressBarSkin.java:56)
at com.sun.javafx.scene.control.skin.ProgressBarSkin$5.invalidated(ProgressBarSkin.java:210)
at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:155)
‚IllegalStateException: Not on FX application thread‘
ist wieder etwas, was sich perfekt für Suchmaschinen eignet
ich schätze auf die Schnelle:
entweder generell an womöglich vorhandene Mechanismen von JavaFX halten,
doch kein eigener Thread sondern z.B. den Task auf offiziell richtigen Weg verwenden,
im Link ist ein allgemeines Tutorial genannt http://docs.oracle.com/javafx/2/swing/jfxpub-swing.htm
welches sich allerdings an Kenntnisse von Swing richtet, was bei dir vielleicht auch nicht so ideal vorhanden ist
oder beim Thread bleiben, aber jede einzelne Aktion, die die GUI verändern,
in ein kleines Kommando an den offizellen GUI-Thread verwandeln
(was sich bei Swing grundsätzlich auch anbietet, nur ohne generelle Fehlermeldung…) Platform.runLater(new Runnable() usw. wie im Link,
aber wichtig dann: nur die einzelnen kurzen Aktionen, nicht die Schleife oder gar das sleep() dort ausführen
rechne den Progresswert noch normal aus, diese lokale Variable final machen, damit von anonymer innerer Klasse zu verwenden, dann das runLater()
ich musste erstmal heftig überlegen wie das überhaupt funktionieren kann,
was machen unbekannte Methoden updateProgress(i, max); und updateMessage(String.valueOf(i));,
wie um alles in der Welt ist das mit einer bestimmten Progressbar verknüpft?
aber testBar.progressProperty().bind(task.progressProperty());
ist eben ein weiterer hochspezifischer Befehl genau für diese Aufgabe,
den kann man doch nur kopieren, kaum selber drauf kommen?
unter http://docs.oracle.com/javafx/2/api/javafx/concurrent/Task.html gar nicht genannt…
also das ist eine so maßgeschneiderte Lösung,
da ist die Frage „vielleicht auch gar nicht so genutzt werden sollt?“ tiefstapelnd
Ich hab ja nicht behauptet das ich da ganz von selbst drauf gekommen bin… wozu gibt es Google?
Leider sind meine Java Kenntnisse sehr beschränkt und meine JavaFX Kenntnisse noch sehr viel geringen. Da ich aber die Aufgabe habe ein kleines aber für mich schon sehr herausforderndes Programm zu schreiben muss ich schauen wie ich an die notwendigen Bausteine komme um mir das „zusammen zu stöpseln“.
evtl. könntest du mir ja ein kurzes allgemeineres Beispiel aufschreiben, wie ich 2 Threads laufen lassen kann.
Thread ist der der den ProgressBar aktuallisiert
Thread ist ein SQL Update auf einer Oracle DB
Das SQL Update hatte ich schon, das mit dem ProgressBar aber eben nicht.
„das mit dem ProgressBar aber eben nicht.“
doch, denn das hast du hier vorliegen
du meinst vielleicht, dass du die Kombination noch nicht hast
und ich sage nicht dass es schlecht ist zu kopieren, poste ja selber nur Links,
sondern ich wundere mich dass du „ganz und gar nicht gut ist“ fragst
wenn du doch offensichtlich ein genau passendes Beispiel gefunden hast
wenn die ProgressBar den Stand der DB-Arbeit darstellen soll, dann reicht vielleicht ein Thread,
der ist so nebenläufig wie es nur geht, nebenläufig-besser wird es auch durch einen zweiten Thread nicht unbedingt,
alle X von insgesamt N fertigen Kommandos (oder schlicht bei jedem Schleifendurchlauf)
könnte der SQL-Thread die ProgressBar updaten,
dabei dann gegebenenfalls auf Platform.runLater() achten,
aber Task mit call() geht wohl auch, falls der DB-Code so nah an der GUI stehen soll und nicht in einen unabhängigen Thread,
ob im Task gesleep()t wird oder DB-Arbeit, das kommt fast aufs Gleiche hinaus
aber testBar.progressProperty().bind(task.progressProperty());
ist eben ein weiterer hochspezifischer Befehl genau für diese Aufgabe,
den kann man doch nur kopieren, kaum selber drauf kommen?
Das ganze nennt sich Bindings (gibt ein ganzes package in JavaFX mit dem Kram) und damit muss man sich schon separat auseinandersetzen damit, das lohnt sich aber. Es gibt auch auf der Tutorial-Seite von JavaFX tolle Erklärungen dazu. Die Felder jeglicher JavaFX-Klassen sind nur noch Properties, die die eigentlichen Werte „verwalten“ und mögliche Veränderungen beobachten. Es gibt Properties für primitive Werte wie int, long, double, boolean usw. und natürlich eine ObjectProperty.
ObjectProperty<Set<String, Krempel>> krempelSet = new SimpleObjectProperty(new Set<String, Krempel>());
Jetzt kann man das Verhalten seiner Komponenten an solche Properties „binden“. Es ist im Prinzip ein gewrappter Listener, man schreibt halt etwas weniger Code:
BooleanExpression be = textField.textProperty().isNotEqualTo("");
irgendeinElement.visibleProperty().bind(be);
Ich wollte ja eigentlich was zu den Threads in JavaFX sagen. Der von SlaterB gebrachte Einwand
ist eben ein weiterer hochspezifischer Befehl genau für diese Aufgabe,
ist vollkommen richtig, den gibt es nur in der ProgressBar. Denn normalerweise gilt, das man mit Task und Service (die in JavaFX zuständigen Klassen für Nebenläufigkeit) nicht direkt an der UI rumschrauben kann.
Das sollte man dann halt mit den besagten Properties lösen, also Property deklarieren (z.B. StringProperty), textProperty eines Labels an diese StringProperty binden und aus dem Thread nur die StringProperty „bearbeiten“. Task und Service unterscheiden sich, soweit ich das verstanden habe, nur in ihrer Wiederverwendbarkeit. Direkte Manipulationen an der UI, die in einem Thread laufen müssen oder sollen, besser mit Platform.runLater() bewerkstelligen.
final static Task<Void> task = new Task<Void>() {
public Void call() throws Exception {
for (double i=0; i<=1; i+=0.01) {
updateProgress(i, 1);
Thread.sleep(100);
System.out.println("In Thread: " + i);
}
return null;
}
};
Und in meiner Methode die beim Drücken eines Buttons vom ProfilController gestartet wird:
demo.ProfileController.testBar = new ProgressBar();
demo.ProfileController.testBar.progressProperty().bind(task.progressProperty());
new Thread(task).start();
mein Problem ist aber nach wie vor, der ProgressBar wird nicht upgedated… :grr:
was heißt ‘nach wie vor’, deine letzte Meldung vom 21.8. ging doch, oder?
updateProgress(i, 1);
mit Kommazahlen von 0 bis 1, funktioniert das?
war früher/ ist in Beispielen nicht eher was von 1-100 zu finden?
genau nachzuschlagen/ auszuprobieren
gehe etwa wieder auf den Stand von Posting #7 zurück, 1-50 geht dort wie zu erwaten?
geht auch von 0-5 in 0.5er Schritten, genau 10 Stufen zu erkennen bei ausreichender Pause?