1 回答

TA貢獻(xiàn)2003條經(jīng)驗(yàn) 獲得超2個(gè)贊
JavaFX 有一個(gè)“事件線程”,負(fù)責(zé)處理按鈕點(diǎn)擊、更新標(biāo)簽和任何其他與 GUI 相關(guān)的任務(wù)。當(dāng)您調(diào)用時(shí)button.setOnAction(e -> doSomething());,當(dāng)您按下按鈕時(shí),doSomething()發(fā)生在 JavaFX 線程上。在此運(yùn)行期間,不會(huì)發(fā)生其他 GUI 事件。這意味著您的界面將完全凍結(jié),從而導(dǎo)致糟糕的用戶體驗(yàn)。
此外,您不能在 JavaFX 線程以外的任何線程上執(zhí)行 GUI 操作,否則您將獲得一個(gè)IllegalStateException. (試著打電話Executors.newSingleThreadExecutor().execute(() -> label.setText("hello"));看看這個(gè)在行動(dòng))
幸運(yùn)的是,JavaFX 提供了解決這個(gè)問題的方法。
首先,也是最簡(jiǎn)單的方法,是在新線程中調(diào)用長時(shí)間運(yùn)行的方法(可能使用ExecutorService上面的 s),當(dāng)您需要修改接口時(shí),將這些調(diào)用包裝在對(duì)Platform.runLater(() -> updateInterface());. 這將發(fā)布updateInterface()到 GUI 線程,并允許它運(yùn)行。
但是,這可能會(huì)很麻煩,因此首選方法是使用Service.
假設(shè)您的長時(shí)間運(yùn)行的計(jì)算返回一個(gè)Double,您創(chuàng)建一個(gè)類 extending Service<Double>,覆蓋它的createTask()方法,并在那里執(zhí)行計(jì)算,如下所示:
public class CalculationService extends Service<Double> {
? ? @Override
? ? protected Task<Double> createTask() {
? ? ? ? return new Task<Double>() {
? ? ? ? ? ? @Override
? ? ? ? ? ? protected Double call() throws Exception {
? ? ? ? ? ? ? ? return doCalculation();
? ? ? ? ? ? }
? ? ? ? };
? ? }
}
然后,在你的控制器中,聲明一個(gè)private final CalculationService service = new CalculationService();
在您的控制器initialize()方法中,您可以將此服務(wù)的輸出綁定到您想要的任何內(nèi)容。例如:
calculationDisplayLabel.textProperty().bind(Bindings.createStringBinding(service.valueProperty()));
// continuously updates the label whenever the service calculates a new value
然后,每當(dāng)您決定要重新開始計(jì)算時(shí),service.restart()如果進(jìn)程正在運(yùn)行,您可以調(diào)用中斷進(jìn)程,并從頭開始。
如果要在值更改時(shí)調(diào)用代碼,請(qǐng)向服務(wù)的值添加一個(gè)偵聽器。例如,如果您希望它在完成后立即重新計(jì)算,請(qǐng)調(diào)用:
service.valueProperty().addListener((obs, old, newValue) -> service.restart());
添加回答
舉報(bào)