JavaFX按钮不会禁用

我有一个任务可能需要几秒钟到几分钟,当我点击按钮执行任务时,它运行任务但不总是禁用按钮A并启用按钮B

这是我正在使用的代码:

 @FXML public void onExecute(ActionEvent event){ btnExecute.setDisable(true); btnStopExec.setDisable(false); new Thread(){ @Override public void run(){ Platform.runLater(() -> { QueryTable qt = new QueryTable(currentMysqlConn, currentDatabase); qt.setTabPane(resultsTabPane); qt.setQuery(queries); qt.executeQueries(); btnExecute.setDisable(false); btnStopExec.setDisable(true); }); } }.start(); } 

如果我注释掉在Platform.runLater()按钮中禁用按钮A被禁用并且按钮B被启用,但是在Platform.runLater()运行之后。 为什么这有时会工作而不是其他人?

根据Platform.runLater(...)的Javadocs ,它

在FX应用程序线程上运行指定的Runnable

因此,后台线程唯一要做的就是安排所有耗时的数据库工作在FX应用程序线程上运行:您的后台线程基本上是多余的,并且在数据库工作运行时您的UI将无响应。

如果发生在btnExecute.setDisable(true);的调用之间呈现帧btnExecute.setDisable(true); 并且您定义的runnable被执行,然后您将看到禁用状态更改。 如果没有,则在同一帧渲染(*)期间执行所有代码,因此您永远不会看到禁用状态更改。

应该从后台线程调用Platform.runLater()来更新UI。 所以你可以按如下方式工作:

 @FXML public void onExecute(){ btnExecute.setDisable(true); btnStopExec.setDisable(false); new Thread(){ @Override public void run(){ QueryTable qt = new QueryTable(currentMysqlConn, currentDatabase); qt.setTabPane(resultsTabPane); qt.setQuery(queries); qt.executeQueries(); Platform.runLater(() -> { btnExecute.setDisable(false); btnStopExec.setDisable(true); }); } }.start(); } 

Platform.runLater(...)是一种非常低级的FX工作方法。 javafx.concurrentjavafx.concurrent定义了更高级别的API:特别是Task类封装后台任务并提供将在FX Application Thread上执行的回调,以便您可以更新UI。 Javadocs有很多例子,但你可以这样做:

 @FXML public void onExecute(){ btnExecute.setDisable(true); btnStopExec.setDisable(false); Task databaseTask = new Task() { @Override public void call(){ QueryTable qt = new QueryTable(currentMysqlConn, currentDatabase); qt.setTabPane(resultsTabPane); qt.setQuery(queries); qt.executeQueries(); return null ; } }; databaseTask.setOnSucceeded( event -> { btnExecute.setDisable(false); btnStopExec.setDisable(true); }); new Thread(databaseTask).start(); } 

(*)这是一个有点不精确的陈述,但它在质量上是正确的。 从技术上讲,渲染线程在FX应用程序线程上执行操作时会阻塞。 (两者不是同一个线程,但它们之间有很大的同步。)因此,在QueryTable qt = new QueryTable(...);的调用之间不可能呈现帧QueryTable qt = new QueryTable(...);btnStopExec.setDisable(true); 。 帧可以在btnStopExec.setDisable(false);之间呈现btnStopExec.setDisable(false); 和runnable的执行(即在QueryTable qt = new QueryTable(...); )。 如果渲染了这样的帧,则会看到禁用状态发生变化; 如果没有,你就不会。 是否发生这种情况仅仅是关于“脉冲”(帧渲染)的调用时间,其目标是每1/60秒发生一次。