Как ждать завершения потока JFrame из приложения JavaFX? - PullRequest
0 голосов
/ 11 июня 2018

Я пытаюсь создать окно JFrame из приложения JavaFX.Я использую Oracle Java 8 и могу делать то, что мне нужно, в Linux, Windows, но не в Mac OS.Это похоже на проблему реализации JVM.Вот мои требования:

  • Мне нужно вызвать метод библиотеки, который создает игровое окно (расширенный класс из JFrame).Мне нужно иметь возможность использовать клавиатуру в игре.
  • Я могу получить доступ к исходному коду библиотеки, но не собираюсь менять исходный код библиотеки
  • Мне нужнообрабатывать информацию об игре после ее завершения, поэтому мой основной поток должен ждать, пока игра не закончится

Я создал пример приложения ниже.Приложение прекрасно работает под Linux и Windows, но в Mac OS, когда я пытаюсь дождаться завершения потока приложения JFrame, зависание приложения и JFrame не отображаются.SwingUtilities.invokeLater не останавливается, но не ожидает завершения потока JFrame.Поскольку мне нужно дождаться потока JFrame, invokeLater для меня не вариант.

JFrameCreator.java

public class JFrameCreator implements Runnable {
    @Override
    public void run() {
        System.out.println("Creating JFrame");
        JFrame frame=new JFrame();
        frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
        frame.setSize(300,300);
        frame.setVisible(true);
        for (int i = 0; i < 100; i++) {
            frame.getContentPane().getGraphics().drawOval(150-i/2,150-i/2,i,i);
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

sample.fxml

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="100.0" prefWidth="200.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
   <children>
      <Button layoutX="51.0" layoutY="10.0" mnemonicParsing="false" onAction="#createJFrame" text="New JFrame" />
      <RadioButton fx:id="cbThread" layoutX="10.0" layoutY="40.0" mnemonicParsing="false" selected="true" text="Thread">
         <toggleGroup>
            <ToggleGroup fx:id="tg" />
         </toggleGroup>
      </RadioButton>
      <RadioButton fx:id="cbInvokeWait" layoutX="10.0" layoutY="60.0" mnemonicParsing="false" text="invokeAndWait" toggleGroup="$tg" />
      <RadioButton fx:id="cbInvokeLater" layoutX="10.0" layoutY="80.0" mnemonicParsing="false" text="invokeLater" toggleGroup="$tg" />
   </children>
</AnchorPane>

Controller.java

public class Controller {
    @FXML RadioButton cbThread;
    @FXML RadioButton cbInvokeWait;
    @FXML RadioButton cbInvokeLater;

    public void createJFrame(javafx.event.ActionEvent actionEvent) {
        Runnable r=new JFrameCreator();
        try {
            if (cbThread.isSelected()) {
                Thread t=new Thread(new JFrameCreator());
                t.start();
                t.join();
            }
            else if(cbInvokeWait.isSelected())
                SwingUtilities.invokeAndWait(r);
            else
                SwingUtilities.invokeLater(r);
        }
         catch (InterruptedException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

Main.java

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
        primaryStage.setTitle("Swing in JavaFX");
        primaryStage.setScene(new Scene(root, 200, 100));
        primaryStage.show();
    }


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

Я также пробовал цикл while с методом Thread.isAlive (), но он также ведет себя как Thread.join ().Как я могу достичь своих требований?

1 Ответ

0 голосов
/ 11 июня 2018

Вы можете использовать один из классов синхронизации, например CountDownLatch.Передайте его своему Runnable и вызовите latch.countDown() в конце метода run().Тем временем ваш поток JavaFX будет приостановлен на latch.await().Однако это замораживает пользовательский интерфейс JavaFX, поэтому это может быть не то, что вам нужно.

Другой вариант - использовать обратный вызов.Что-то вроде:

public class JFrameCreator implements Runnable {

    private final Runnable onFinished;

    public JFrameCreator(Runnable onFinished) {
        this.onFinished = onFinished;
    }

    @Override
    public void run() {
        // do your work...
        Platform.runLater(onFinished); // to communicate to JavaFX Application
                                       // Thread that JFrameCreator is complete
    }

}

Этот второй параметр не заставит поток JavaFX ждать , но он позволит вам реагировать в соответствующее время.Вы можете изменить тип onFinished на любой другой;например Consumer, если вы хотите передать обратный вызов некоторому объекту.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...