简体   繁体   中英

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.

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.

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. This way you can lock/unlock those threads as you wish and the GUI will not be frozen.

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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