簡體   English   中英

JavaFX-從GUI接收事件后返回主線程

[英]JavaFX - coming back to main thread after receiving event from gui

我正在編寫JavaFX應用程序,並且意識到FX線程上發生了太多事情。 根本原因之一是gui事件(如按鈕單擊)在FX線程上產生了后端操作。 實際上,剛收到事件后,我們就進入了FX線程,因此任何其他調用都將保留在該線程上。 有什么方法可以簡單地返回到MAIN應用程序線程,然后在需要時返回Platform.runLater,或者我必須使用例如RX或某些執行程序服務來處理它?

謝謝

退出事件循環的方法非常簡單-只是Java。 使用通常使用的任何東西-執行程序,隊列等。

例如,要在“后台”完成某項操作然后更新GUI,您可以執行以下操作

final Executor backgroundWorker = Executors.newSingleThreadExecutor();
...
backgroundWorker.execute(()-> // from the EventLoop into the Worker
{
    val result = doThatLongRunningTask();
    Platform.runLater(() -> // back from the Worker to the Event Loop
    {
        updateUiWithResultOfLongRunningTask(result);
    }
});

我通常希望將main線程分配給事件循環,並使用自定義執行程序進行后台工作(因為后台工作是特定於應用程序的,因此可能需要更多線程等)。


如果出於任何異乎尋常的原因(實際上沒有我能想到的),您反過來想要它:

因此,要將主線程用作執行程序,我們需要做的是:

public final class MyApp extends Application {
    private static final Logger LOG = LoggerFactory.getLogger(MyApp.class);
    private static final Runnable POISON_PILL = () -> {}; 
    private final BlockingQueue<Runnable> tasks = new LinkedBlockingQueue<>();
    private final Executor backgroundWorker = this::execute;
    private final Future<Void> shutdownFuture = new CompletableFuture<>();
    private final Executor eventLoop = Executors.newSingleThreadExecutor();

    /** Get background worker */
    public Executor getBackgroundWorker() {
        return backgroundWorker;
    } 

    /** Request backgroun worker shutdown */
    public Future shutdownBackgroundWorker() {
        execute(POISON_PILL);
        return shutdownFuture;
    }

    private void execute(Runnable task) {
        tasks.put(task);
    }

    private void runWorkerLoop() throws Throwable {
        Runnable task;
        while ((task = tasks.take()) != POISON_PILL) {
            task.run();
        }
        shutdownFuture.complete(null);
    }

    public static void main (String... args) throws Throwable {
        final MyApp myApp = new MyApp(args);        

        LOG.info("starting JavaFX (background) ...");
        eventLoop.execute(myApp::launch);

        LOG.info("scheduling a ping task into the background worker...");
        myApp.runLater(() -> {
            LOG.info("#1 we begin in the event loop");
            myApp.getBackgroundWorker().execute(() -> {
                LOG.info("#2 then jump over to the background worker");
                myApp.runLater(() -> {
                    LOG.info("#3 and then back to the event loop");
                });
            });
        });

        LOG.info("running the backgound worker (in the foreground)...");
        myApp.runWorkerLoop();
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM