简体   繁体   English

如何从事件处理程序向 Java FX 主线程发出信号?

[英]How to signal the Java FX main thread from an event handler?

I was working on a chess game application and I decided to make the main game loop wait until the user selects a field.我正在开发一个国际象棋游戏应用程序,我决定让主游戏循环等到用户选择一个字段。 To do this, I made a java.util.concurrent.locks.Condition object, on which the main Application Thread waits and which is signaled by the event handler once the user has clicked somewhere.为此,我制作了一个java.util.concurrent.locks.Condition object,主应用程序线程在其上等待,并且一旦用户单击某处,事件处理程序就会发出信号。

However, the click handler is never run, and as such, the entire program is frozen, since the condition is never signaled.但是,单击处理程序永远不会运行,因此,整个程序被冻结,因为条件从未发出信号。 Is there some way to make sure that the handler is run, or are events just not checked while the main thread is waiting on a condition?有什么方法可以确保处理程序运行,或者在主线程等待条件时不检查事件?

(Almost) minimal example: (几乎)最小的例子:

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

import java.util.concurrent.locks.*;

public class EventHandlerLockExample extends Application {
    public static final Lock lock = new ReentrantLock();
    public static final Condition availableClick = lock.newCondition();
    public static int x, y;

    @Override
    public void start(Stage primaryStage) throws InterruptedException{
        Canvas can = new Canvas(128, 128);
        Scene scene = new Scene(new Group(can));
        scene.setOnMouseClicked(event -> {
            lock.lock();
            try{
                x = (int) event.getSceneX();
                y = (int) event.getSceneY();
                availableClick.signal();
            }finally{
                lock.unlock();
            }
        });
        primaryStage.setTitle("Chess Game");
        primaryStage.setScene(scene);
        primaryStage.show();
        lock.lock();
        try{
            availableClick.await();
            can.getGraphicsContext2D().setFill(Color.RED);
            can.getGraphicsContext2D().fillOval(x, y, 5, 5);
            System.out.printf("Click[x=%d ,y=%d]%n", x, y);
        }finally{
            lock.unlock();
        }
    }

    public static void main(String[] args){
        launch(args);
    }
}

I would recommend that you separate the UI, computer, and the player with multi threading.我建议您使用多线程将 UI、计算机和播放器分开。

JavaFX GUI will be frozen and could cause issues (such as listening for the click) if you are pausing its thread, so what I would do is create a thread for the computer player and a thread for the actual player. JavaFX GUI 将被冻结,如果您暂停其线程,可能会导致问题(例如监听点击),所以我要做的是为计算机播放器创建一个线程,为实际播放器创建一个线程。 This way you can lock/unlock those threads as you wish and the GUI will not be frozen.这样,您可以根据需要锁定/解锁这些线程,并且 GUI 不会被冻结。

To implement multi threading you can use the following code:要实现多线程,您可以使用以下代码:

private ScheduledExecutorService scheduledExS;
private ScheduledFuture<?>       scheduled;
/* Start thread to periodically execute getData() with 0ms starting delay every 500ms  */
scheduledExS = Executors.newScheduledThreadPool(1);
scheduled    = scheduledExS.scheduleAtFixedRate(getData, 0, 500, TimeUnit.MILLISECONDS);
/* Stop thread when finished */
scheduledExS.shutdownNow();

where getData is a runnable function其中getData是可运行的 function

Runnable getData = () -> { /* Do something */ };

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM