JavaFX按钮不会禁用

时间:2014-11-16 04:04:33

标签: java javafx

我的任务可能需要几秒钟到几分钟,当我点击按钮执行任务时,它会运行任务,但并不总是禁用按钮A并启用按钮{{ 1}}。

以下是我正在使用的代码:

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运行后。为什么这有时会起作用而不是其他人呢?

1 个答案:

答案 0 :(得分:3)

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

  

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

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

如果在调用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(...)对外汇工作来说是一种非常低级的方法。 javafx.concurrent包为此定义了更高级别的API:特别是Task类封装后台任务并提供将在FX应用程序线程上执行的回调,以便您可以更新UI。 Javadocs有很多例子,但你可以这样做:

@FXML
public void onExecute(){
    btnExecute.setDisable(true);
    btnStopExec.setDisable(false);
    Task<Void> databaseTask = new Task<Void>() {
        @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(...);btnStopExec.setDisable(true);的调用之间无法呈现帧。帧可以在btnStopExec.setDisable(false);和runnable的执行之间(即QueryTable qt = new QueryTable(...);之前)进行渲染。如果渲染了这样的帧,则会看到禁用状态发生变化;如果没有,你就不会。是否发生这种情况仅仅是关于“脉冲”(帧渲染)的调用时间,这些目标是每1/60秒发生一次。