JavaFX按钮不会禁用 [英] JavaFX buttons don't disable

查看:448
本文介绍了JavaFX按钮不会禁用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a task that can take a few seconds to a few minutes, and when I click on the button to execute the task, it runs the task but does not always disable button A and enable button B.

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

Here is the code that I am using:

@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();
}

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

If I comment out the button disabling in Platform.runLater() button A gets disabled and button B get enabled, but after Platform.runLater() runs. Why does this work sometimes and not others?

推荐答案

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


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

Runs the specified Runnable on the FX Application Thread

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

So the only thing your background thread does is to schedule all your time-consuming database work to run on the FX Application Thread: your background thread is basically redundant, and your UI will be unresponsive while the database work is running.

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

If it happens that a frame is rendered between the calls to btnExecute.setDisable(true); and the runnable you define getting executed, then you will see the disabled state change. If not, then all your code gets executed during the same frame rendering(*), so you will never see the disabled state change.

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

Platform.runLater() should be called from a background thread just to update the UI. So you could make this work as follows:

@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:特别是 任务 类封装后台任务并提供将在FX上执行的回调应用程序线程,以便您可以更新UI。 Javadocs有很多例子,但你可以这样做:

Platform.runLater(...) is a pretty low-level approach for FX work. The javafx.concurrent package defines a higher-level API for this: in particular the Task class encapsulates a background task and provides callbacks that will be executed on the FX Application Thread so you can update the UI. The Javadocs have copious examples, but you could do:

@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秒发生一次。

(*) This is a somewhat imprecise statement, but it's qualitatively correct. Technically, the rendering thread blocks while actions are being executed on the FX Application Thread. (The two are not the same thread, but they have a large amount of synchronization between them.) Thus it's impossible for a frame to be rendered between the call to QueryTable qt = new QueryTable(...); and btnStopExec.setDisable(true);. It is possible for a frame to be rendered between btnStopExec.setDisable(false); and the execution of your runnable (i.e before QueryTable qt = new QueryTable(...);). If such a frame is rendered, you see the disabled state change; if not, you don't. Whether or not that happens is just down to the timing of the calls with respect to the "pulses" (frame renderings), which are targeted to happen every 1/60th second.

这篇关于JavaFX按钮不会禁用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆