【问题标题】:How do i restart an application in JavaFx, built with FXML?如何重新启动使用 FXML 构建的 JavaFx 中的应用程序?
【发布时间】:2015-02-24 09:39:34
【问题描述】:

假设我有一个带有按钮的窗口。每次按下该按钮时,我都希望处理当前窗口并显示一个新窗口。

在 Swing 中,这很容易,但我在 JavaFx 中找不到它的语法? 那么在这种情况下,使用我的示例代码,我该怎么做呢?

public class Main extends Application {

    Parent root;
    Scene scene;

    @Override
    public void start(Stage primaryStage) throws Exception {
        root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));

        scene = new Scene(root);

        primaryStage.setScene(scene);

        primaryStage.sizeToScene();
        primaryStage.setResizable(false);

        primaryStage.show();


        root.setOnMouseClicked((MouseEvent mouseEvent) -> {
            if (mouseEvent.getButton().equals(MouseButton.PRIMARY)) {
                if (mouseEvent.getClickCount() == 2) {



                        Stage stage = new Stage();
                        stage.setScene(primaryStage.getScene());
                        stage.show();
                        primaryStage.close();


                }
            }
        });
    }


    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
     }

尝试创建新窗口:http://sv.tinypic.com/r/1jkq4w/8

FXML:

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.paint.*?>
<?import javafx.scene.text.*?>

<VBox prefHeight="430.0" prefWidth="640.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="blackjack.FXMLDocumentController">
  <children>
    <AnchorPane maxHeight="-1.0" maxWidth="-1.0" prefHeight="-1.0" prefWidth="-1.0" VBox.vgrow="ALWAYS">
      <children>
            <Label fx:id="labelPlayerTotal" layoutX="510.0" layoutY="335.0" prefHeight="15.0" prefWidth="121.0" text="Playertotal:" />
            <Label fx:id="labelDealerTotal" layoutX="510.0" layoutY="359.0" prefHeight="15.0" prefWidth="112.0" text="Dealertotal:" />
            <TextArea fx:id="dealerArea" layoutY="29.0" prefHeight="159.0" prefWidth="503.0" />
            <TextArea fx:id="playerArea" layoutY="244.0" prefHeight="159.0" prefWidth="503.0" />
            <Button fx:id="stayButton" layoutX="512.0" layoutY="173.0" mnemonicParsing="false" onAction="#drawCardForDealer" prefHeight="25.0" prefWidth="72.0" text="STAY" />
            <Button fx:id="hitButton" layoutX="512.0" layoutY="130.0" mnemonicParsing="false" onAction="#drawCardForPlayer" prefHeight="25.0" prefWidth="72.0" text="HIT" />
            <Label fx:id="labelWinner" layoutX="104.0" layoutY="208.0" prefHeight="15.0" prefWidth="296.0" />
            <MenuBar fx:id="helpBar">
              <menus>
                <Menu mnemonicParsing="false" text="Help">
                  <items>
                    <MenuItem mnemonicParsing="false" onAction="#aboutApplication" text="About" />
                  </items>
                </Menu>
              </menus>
            </MenuBar>
      </children>
    </AnchorPane>
  </children>
</VBox>

【问题讨论】:

  • 您是否需要处理窗口或只处理当前的 fxml 也适合您?
  • "..每次按下该按钮时,我都希望释放当前窗口并显示一个新窗口。在 Swing 中,这很简单,.." 简单也许,但不推荐。请参阅The Use of Multiple JFrames, Good/Bad Practice? 如果 Java-FX 将开发人员限制在一个单一的“框架”中,那么它必须是有利于它的东西。
  • @AndrewThompson 谢谢安德鲁,我的 JavaFX 应用程序中需要这个重启按钮,这对我的应用程序来说非常必要。这可能吗?
  • 你在 Swing 中使用什么来重启应用程序?
  • @ItachiUchiha "this.dispose(处理当前窗口),new Window().setVisible(true);" .. 如果我没记错语法。

标签: java swing javafx fxml


【解决方案1】:

您可以通过调用 hide()close() 来隐藏(即处置)窗口。 您可以使用与之前使用的代码完全相同的代码来显示一个新窗口:

                primaryStage.close();

                Stage stage = new Stage();

                root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));

scene = new Scene(root);

stage.setScene(scene);

stage.sizeToScene();
stage.setResizable(false);

stage.show();

但这对于您想要实现的目标来说似乎太过分了。为什么不直接替换现有场景的根,使用现有的舞台?

try {
    scene.setRoot(FXMLLoader.load(getClass().getResource("FXMLDocument.fxml")));
} catch (Exception exc) {
    exc.printStackTrace();
    throw new RuntimeException(exc);
}

请注意(无论您这样做),您现在已经替换了场景的根;新根没有与之关联的相同鼠标处理程序。如果您使用第二种方法,您可以将处理程序放在场景中(不会更改)。或者,也许更好的是,您可以在 FXML 和控制器中定义侦听器:

<VBox prefHeight="430.0" prefWidth="640.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="blackjack.FXMLDocumentController"
fx:id="root"
onMouseClicked="reload">
<!-- ... -->
</VBox>

还有控制器:

package blackjack ;

public class FXMLDocumentController {

    // ...

    @FXML
    private VBox root ;

    // ...

    @FXML
    private void reload() throws Exception {

        // Really, it would be way better here to reset the whole UI to its initial
        // state, instead of reloading it from scratch. This should work as a 
        // quick hack though.
        Scene scene = root.getScene();
        scene.setRoot(FXMLLoader.load(Main.class.getResource("FXMLDocument.fmxl")));
    }

    // ...
}

【讨论】:

  • 效果很好。当我双击时,当前窗口被释放并显示一个新窗口。伟大的!但是当我用新窗口再次尝试时,该功能不起作用。你知道为什么它只在第一次起作用吗?难道不能用 System.exit 杀死所有东西并加载一个新的 UI 吗?
  • 哦,是的,因为鼠标监听器只添加到第一个根,然后被替换。我会更新的。
  • 是的,我同意重置整个 UI 更好。这是非常混乱的,但还是谢谢你。如果我要重置整个 UI,System.exit 然后加载 fxml 就足够了吗?或者我该怎么做?
  • 我的意思是“重置所有 UI 组件”。 (如果这太难编码,那么您可能需要了解一些设计策略,尽管这是一个更高级的主题。)这个想法是对系统的影响更小,而不是更多。如果您调用System.exit(...);,您将完全退出应用程序,因此之后的任何代码都不会被执行。我认为按照我展示的方式在控制器中重新加载是一个合理的折衷方案。
  • 好的,谢谢。我对这么小的东西需要做多少工作感到惊讶。挥杆要容易得多。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-12
  • 2011-03-12
  • 1970-01-01
  • 2016-04-19
  • 1970-01-01
  • 1970-01-01
  • 2019-04-10
相关资源
最近更新 更多