【问题标题】:JavaFX updates graphic only using debug and breakpointsJavaFX 仅使用调试和断点更新图形
【发布时间】:2016-06-23 09:23:32
【问题描述】:

我正在通过 RMI 使用 javaFX 为棋盘游戏创建 GUI。 我有很多问题,因为在找到更新 GUI 的方法后,如果我不在某行放置切换断点,我将无法真正更新 GUI。

如果我不以调试模式启动我的客户端,图形似乎不会进行更新,它们只是出现并且什么都没有发生。

此外,如果我没有将切换按钮放在代码的指定行中,而是将其放在另一行(在方法调用序列的更深处),则不会发生任何事情。所以客户端线程不会停止;就好像它不像断点那样进行方法调用。 我在同一台机器上启动所有客户端,只有一个(使用切换断点)得到更新。

现在我将向您展示我的代码。

javafx 从一个名为 RMIGUIView.java 的类开始

@Override
public synchronized void run() {
    waiting = true;
    pause();
    guiDisplayer = new GUIDisplayer();
    (new Thread(() -> guiDisplayer.startGUI())).start();
    waiting = false;
    do {
        state.acceptView(this);
    } while(!endGame);
}

然后我启动 GUI(在启动方法中,我按照此处的建议将舞台保存在控制器上 Passing Parameters JavaFX FXML

public class GUIDisplayer extends Application {

private StartTurnState currentState;
private Stage stage;

public void start(Stage stage) throws Exception {
    GUIController controller = new GUIController();
    FXMLLoader fxmlLoader = new FXMLLoader();
    Parent root = fxmlLoader.load(getClass().getResource("sceneMap.fxml"));
    stage.setTitle("Council of Four");
    Scene newScene = new Scene(root);
    stage.setScene(newScene);
    stage.show();
    controller.setStage(stage);
}

public static void startGUI() {
    Application.launch();
} }

gui 启动后,我返回 RMIGUIView.java 并执行此操作

@Override
public void visit(StartTurnState currentState) {
    GUIController guiController = new GUIController();
    guiController.updateGUI(currentState);
}

这里是我的控制器类,如果我想发生某些事情,我必须在其中放置切换断点(请阅读 cmets 类)

public class GUIController {

@FXML
ArrayList<ImageView> citiesImagesList;
@FXML
Group group;
@FXML
TableView<Player> players;
@FXML
TableColumn<Player, String> playerName;
@FXML
TableColumn<Player, String> victoryPoints;
@FXML
TableColumn<Player, String> coins;
@FXML
TableColumn<Player, String> assistants;
@FXML
TableColumn<Player, String> nobilityPoints;
@FXML
ImageView A;
@FXML
ImageView B;
@FXML
ImageView C;
@FXML
ImageView D;
@FXML
ImageView E;
@FXML
ImageView F;
@FXML
ImageView G;
@FXML
ImageView H;
@FXML
ImageView I;
@FXML
ImageView J;
@FXML
ImageView K;
@FXML
ImageView L;
@FXML
ImageView M;
@FXML
ImageView N;
@FXML
ImageView O;
@FXML
ImageView king;

private static StartTurnState currentState;
private static GUIController self = null;
private static Stage stage;

public GUIController() {
    self = this;
}

private void placeRewardToken(Group group, List<ImageView> citiesImagesList) {
    Map<String, City> citiesMap = GUIController.currentState.getGameMap().getCitiesMap();
    for (ImageView imageView : citiesImagesList) {
        City city = citiesMap.get(imageView.getId().toString());
        if (city instanceof NormalCity) {
            RewardToken rewardToken = ((NormalCity) city).getRewardToken();
            Text text = new Text();
            text.setText(rewardToken.toString());
            text.setX(imageView.getLayoutX() + 5.00);
            text.setY(imageView.getLayoutY());
            text.toFront();
            text.setFont(Font.font("Verdana", 12));
            text.setFill(Color.MAGENTA);
            group.getChildren().add(text);
        }

    }

}

private void setPlayerSet() {
    Platform.setImplicitExit(false);
    Scene scene = stage.getScene();
    ObservableList<Player> playersList = FXCollections.observableArrayList();
    playersList.addAll(GUIController.currentState.getPlayerSet().getPlayers());
    TableView<Player> playerTable = (TableView<Player>) scene.lookup("#players");
    TableColumn<Player, String> playersName = ((TableColumn<Player, String>) playerTable.getColumns().get(0));
    playersName.setCellValueFactory(new PropertyValueFactory<Player, String>("name"));
    TableColumn<Player, String> victoryPoints = ((TableColumn<Player, String>) playerTable.getColumns().get(1));
    victoryPoints.setCellValueFactory(new PropertyValueFactory<Player, String>("victoryPoints"));
    TableColumn<Player, String> coins = ((TableColumn<Player, String>) playerTable.getColumns().get(2));
    coins.setCellValueFactory(new PropertyValueFactory<Player, String>("coins"));
    TableColumn<Player, String> assistants = ((TableColumn<Player, String>) playerTable.getColumns().get(3));
    assistants.setCellValueFactory(new PropertyValueFactory<Player, String>("assistants"));
    TableColumn<Player, String> nobilityPoints = ((TableColumn<Player, String>) playerTable.getColumns().get(4));
    nobilityPoints.setCellValueFactory(new PropertyValueFactory<Player, String>("nobilityTrackPoints"));
    playerTable.setItems(playersList);
}

private void placeKing(ImageView king, List<ImageView> citiesImagesList) {
    for (ImageView imageView : citiesImagesList) {
        if (imageView.getId().toString().equals(GUIController.currentState.getKing().getPosition().getName())) {
            king.setX(imageView.getLayoutX());
            king.setY(imageView.getLayoutY());
        }
    }
}

@FXML
public void initialize() {
    self = this;
}

public void setStage(Stage stage) {
    this.stage = stage;
}

public void updateGUI(StartTurnState state) {
    GUIController.currentState = state;
    updateMap(); //here I should set my toggle breakpoint
}

private void updateMap() {
    Scene scene = stage.getScene();
    List<ImageView> citiesImagesList = new ArrayList<>();
    citiesImagesList.add((ImageView) scene.lookup("#A"));
    citiesImagesList.add((ImageView) scene.lookup("#B"));
    citiesImagesList.add((ImageView) scene.lookup("#C"));
    citiesImagesList.add((ImageView) scene.lookup("#D"));
    citiesImagesList.add((ImageView) scene.lookup("#E"));
    citiesImagesList.add((ImageView) scene.lookup("#F"));
    citiesImagesList.add((ImageView) scene.lookup("#G"));
    citiesImagesList.add((ImageView) scene.lookup("#H"));
    citiesImagesList.add((ImageView) scene.lookup("#I"));
    citiesImagesList.add((ImageView) scene.lookup("#J"));
    citiesImagesList.add((ImageView) scene.lookup("#K"));
    citiesImagesList.add((ImageView) scene.lookup("#L"));
    citiesImagesList.add((ImageView) scene.lookup("#M"));
    citiesImagesList.add((ImageView) scene.lookup("#N"));
    citiesImagesList.add((ImageView) scene.lookup("#O"));
    ImageView king = (ImageView) scene.lookup("#king");
    Group group = (Group) scene.lookup("#group");
    setPlayerSet(); //if I try setting here my toggle the thread doesent stop as the method updateGui() is never called
    placeKing(king, citiesImagesList);
    placeRewardToken(group, citiesImagesList);
} }

希望你能理解我的问题。如果您不明白某些内容,我将编辑我的问题。我在 Stackoverflow 上没有找到类似的东西。

提前感谢您的帮助。

编辑: 我试图按照 James_D 的建议重写代码 这是我对 GUI 更新的新调用。

    @Override
public void visit(StartTurnState currentState) {
    guiDisplayer.setState(currentState);
    Platform.runLater(()-> guiDisplayer.run());
}

我还修改了 GUIDisplayer 类

public class GUIDisplayer extends Application implements Runnable{

private StartTurnState currentState;
private Stage stage;
static GUIController guiController;

public void start(Stage stage) throws Exception {
    GUIController controller = new GUIController();
    FXMLLoader fxmlLoader = new FXMLLoader();
    Parent root = fxmlLoader.load(getClass().getResource("sceneMap.fxml"));
    stage.setTitle("Council of Four");
    Scene newScene = new Scene(root);
    stage.setScene(newScene);
    stage.show();
    controller.setStage(stage);
    setController(controller);
}

public static void startGUI() {
    Application.launch();
}

public void setState(State state) {
    currentState = (StartTurnState) state;
}

public static void setController(GUIController controller) {
    guiController = controller;
}

@Override
public void run() {
    guiController.doUpdateGUI(currentState);

} }

runLater 方法调用似乎被忽略了,也许我在这种情况下被 javadoc 描述了

如果在 JavaFX 运行时关闭后调用此方法,则该调用将被忽略:不会执行 Runnable,也不会抛出异常。

如果我删除 runLater 并添加切换断点,我仍然可以修改 GUI。

【问题讨论】:

  • 您的棋盘游戏需要快速更新吗?
  • 它需要在每个玩家回合开始时更新,至少每 5 分钟更新一次
  • 通常在您的代码中遵循这个方向:避免在 javaFX 线程之外更改 javaFX SceneGraph(如果您不确定在哪个线程中使用 Platform.isFxApplicationThread()),否则您必须使用 Platform.runLater () 但不要过度使用它会导致应用程序滞后。要在其他线程中运行代码检查docs.oracle.com/javafx/2/threads/jfxpub-threads.htm。我问它更新速度有多快,以防你想使用 javaFX AnimationTimer 快速更新download.java.net/jdk8/jfxdocs/javafx/animation/…

标签: java user-interface debugging javafx breakpoints


【解决方案1】:

在尝试从其他线程(javafx 应用程序线程除外)更新 gui 时,您应该使用 Paltform.runLater( () -&gt; doUpdateGUI() ); 比你的 gui 会正确更新。 检查javafx concurrency

【讨论】:

  • 我已经修改了我的访问,像这样调用 runLater。 @Override public void visit(StartTurnState currentState) { GUIController guiController = new GUIController(); Platform.runLater(()->guiController.doUpdateGUI(currentState));我还在控制器中创建了调用 updateGUI(currentState) 的 che 方法 doUpdateGUI 但什么也没发生,当它应该刷新我的 GUI 时?
  • Platform.runLater(...) 基本上会尽快在 FX 应用程序线程上运行。不要关心方法的名称,它只是表明该块内的代码不一定会在 runLater(...) 调用之后的代码之前完成。我认为@guleryuz 是正确的:这听起来绝对像是一个线程问题,而且您似乎在某处阻塞了 FX 应用程序线程。
  • 我在调用 runLater() 之前尝试过 Platform.setImplicitExit(false) 以强制 runLater(),现在它进入 updateGUI() 但对阶段的引用为空,我得到一个空指针异常。为什么我失去了这个参考?
  • 我无法真正遵循您的代码。似乎有一些字段被任意设置为静态,并且到处都是从非静态上下文调用静态方法。但是您几乎任意地创建了许多GUIController 的实例,这没有任何意义:当您调用load() 时,控制器实例是由FXMLLoader 为您创建的。您可能应该重新组织您的代码,以便它从加载程序中检索该实例并仅使用该实例;否则无法理解发生了什么。
  • 哦,另外,Platform.setImplicitExit(...)Platform.runLater(...) 没有任何关系。这只是意味着外汇平台不会在最后一个窗口关闭时自动退出;您可能出于其他原因需要它,但它不会“强制runLater(...)”(无论这意味着什么)。
猜你喜欢
  • 1970-01-01
  • 2014-10-15
  • 2013-03-13
  • 2022-01-09
  • 1970-01-01
  • 2019-07-01
  • 2015-10-16
  • 2018-04-19
  • 1970-01-01
相关资源
最近更新 更多