[英]JavaFX - Thread hangs, and I can't figure out how to run my loop outside the UI thread
朋友。 這是stackoverflow的新功能,也是JavaFX的新功能。 抱歉,如果我弄亂了任何命名法,並且有點冗長,但是我確實將代碼縮減為一個最小的“有效”示例。 (下面的代碼會掛起,除非您注釋掉while循環,如代碼本身所述)
我試圖弄清楚如何使Slider
在單擊“喚醒”按鈕后連續更改其值,並在單擊“睡眠”按鈕后停止更改值。 為了便於討論,可以說它隨機將值更改為0到99之間的整數。
從我讀這么遠 (我已經讀了很多,但這些都是最近的兩個例子),看來我應該能夠使用Platform.runLater()
或updateMessenger()
來避免運行無限-直到UI線程上的my-sleep-button-breaks-it循環為止。 到目前為止,我沒有實現前者,但是我仍然不確定如何實現后者。
我還嘗試學習有關屬性綁定的信息,以便可以在更改中間變量(我稱為state
並創建)時在UI線程中更改Slider.valueProperty
(在UI線程中更改UI元素是有意義的...對嗎?)。從背景線程上的stateObject
類中stateObject
。 后台線程計算完要提供給滑塊的值后,它將更改state
的值,該值綁定到Slider
的值。 我以為將值計算分為后台線程,將Slider
值更改為UI線程可以解決問題,但我一直遇到掛斷或臭名昭著的IllegalStateException
異常, Not on FX application thread
我不完全確定Platform.runLater()
魔術應該如何工作,但是無論我在其中運行可運行接口還是在Thread()
,我仍然遇到麻煩。
對於這些嘗試為什么失敗/如何使事情起作用的任何幫助或解釋,將不勝感激。
干杯,邁克
import javafx.application.*;
import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.layout.*;
import javafx.scene.control.*;
import javafx.geometry.*;
//Not sure which of these, if any, I actually need
import javafx.event.*;
import javafx.concurrent.*;
import javafx.beans.property.*;
public class MWE extends Application {
//Main method
public static void main(String[] args) {
launch(args);
}
//Class fields
Button sleepBtn, wakeBtn;
Slider displaySldr;
boolean wakeful = true;
//state property class
class stateObject {
//Store the property
private DoubleProperty state = new SimpleDoubleProperty();
//Define getter for property value
public final double getState() {
return state.get();
}
//Define setter for property value
public final void setState(double val) {
state.setValue(val);
}
//Define getter for property itself
public DoubleProperty stateProperty() {
return state;
}
}
//Create state
stateObject state = new stateObject();
//Start method
@Override
public void start(Stage primaryStage) {
//Create top-level pane to store nodes into for the scene
VBox mainPane = new VBox(20);
mainPane.setAlignment(Pos.CENTER);
//Create buttons
sleepBtn = new Button("Sleep");
sleepBtn.setOnAction(e -> NPSleep());
wakeBtn = new Button("Wake");
wakeBtn.setOnAction(e -> NPWake());
//Lay out buttons
VBox buttonsBox = new VBox(10);
buttonsBox.getChildren().addAll(wakeBtn,sleepBtn);
buttonsBox.setAlignment(Pos.CENTER);
//Create slider to be change continuously by clicking wakeBtn once
//Slider should stop changing when sleepBtn is clicked
displaySldr = new Slider(0,100,50);
displaySldr.setMajorTickUnit(25);
displaySldr.setMinorTickCount(24);
displaySldr.setSnapToTicks(true);
displaySldr.setShowTickMarks(false);
displaySldr.setShowTickLabels(true);
//Make property event. When 'state' changes, change displaySldr value
state.stateProperty().addListener(
(observable,oldvalue,newvalue) ->
displaySldr.setValue(newvalue.intValue())
);
//Organize labels and sliders
VBox LSPane = new VBox(10);
LSPane.getChildren().addAll(displaySldr);
LSPane.setAlignment(Pos.CENTER);
//Organize sub-panes into top-level pane, mainPane
mainPane.getChildren().addAll(LSPane,buttonsBox);
//Set the scene
Scene mainScene = new Scene(mainPane);
//Set the stage
primaryStage.setTitle("oh god please work");
primaryStage.setScene(mainScene);
primaryStage.show();
}
private void NPWake() {
Runnable wakeyWakey = () -> {
while (wakeful == true) { //Commenting out the while loop and
//leaving the command allows program to run fine
//but slider changes only once, not continuously
state.setState( Math.floor(Math.random()*100) );
try{
Thread.sleep(300);
} catch (InterruptedException ie) {
}
}
};
Platform.runLater(wakeyWakey);
// Thread wakeThread = new Thread(wakeyWakey); //
// wakeThread.start(); // This doesn't work either
}
private void NPSleep() {
if (wakeful == true) {
wakeful = false;
}
}
}
您不需要具有State Object
,因為您仍然必須更新JavaFX Application Thread
上的值,因此它違背了創建此類對象的想法。 您可以刪除所有與State Object
相關的代碼。 以下代碼是您的解決方案的修復程序:
private void NPWake() {
Thread t = new Thread(() -> {
while (wakeful) {
try {
Platform.runLater(() -> {
displaySldr.setValue(Math.floor(Math.random() * 100));
});
Thread.sleep(300);
}
catch (Exception e) {}
}
});
t.start();
}
Button
onAction
是在JavaFX Application Thread
上處理的,在任何情況下,除非它是它自己的內部結構,否則我們都不希望在該線程上運行無限循環,因為該循環只會使該線程掛起。 因此,我們創建了一個new Thread t
,該new Thread t
將具有該循環,並且在其主體中將調用JavaFX Application Thread
以提交更改。 收集到的信息,必須在JavaFX Application Thread
上對UI / JavaFX屬性進行更改。 Platform.runLater( "some code" )
意味着將來將在JavaFX Application Thread
上(如果線程不忙,幾乎是立即執行)執行“某些代碼”。
至於此類應用程序的設計,我建議您看看AnimationTimer
- https: //docs.oracle.com/javase/8/javafx/api/javafx/animation/AnimationTimer.html或Timeline
- https:/ /docs.oracle.com/javase/8/javafx/api/javafx/animation/Timeline.html 。 它們都在JavaFX Application Thread
上運行。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.