java 如何在显示窗口之前更改 JavaFX 中的 FXML 控制器变量值?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14017542/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 14:45:12  来源:igfitidea点击:

How do I Change FXML Controller Variable Values in JavaFX before Showing Window?

javajavafx-2javafx

提问by calben

I want to change the labels and text in a popup FXMLwindow before it is shown. This is being done because all of the Helpitems will be very similar and I wanted to make a template FXMLand then change the values of the labels and text area accordingly to reduce coding.

我想在FXML显示之前更改弹出窗口中的标签和文本。这样做是因为所有帮助项目都非常相似,我想制作一个模板FXML,然后相应地更改标签和文本区域的值以减少编码。

I'm surprised I haven't come across a template method in JavaFXthough. If there's a better way to go about this, please do suggest it.

我很惊讶我还没有遇到模板方法JavaFX。如果有更好的方法来解决这个问题,请提出建议。

For the task at hand, I have the following:

对于手头的任务,我有以下几点:

@FXML
private void documentationAction(ActionEvent action) throws IOException {
    Stage dialogue = new Stage();
    Parent root = null;
    FXMLLoader loader = new FXMLLoader();
    root = loader.load(getClass().getResource("dialogues/dialogue.fxml"));
    Scene scene = new Scene(root);
    /*
     * change text values in title (Label) and text (TextArea)
     * and change the behavior of the findMore button
     */
    dialogue.setTitle("Documentation");
    dialogue.setScene(scene);
    dialogue.show();
}

I would like to be able to change variables inside the FXML file, for which I've made gettersand settersin the controller class, but I can't figure how to do this.

我希望能够改变内部变量FXMl文件,为此,我做了getters,并setters在控制器类,但我想不出如何做到这一点。

Is there a way? It seems like it would be necessary for changing information between windows in multi-windowed applications, so I'm sure there's something simple that I'm missing.

有办法吗?在多窗口应用程序中更改窗口之间的信息似乎是必要的,所以我确定我遗漏了一些简单的东西。

UPDATE Code for controller:

控制器的更新代码:

public class DialogueController implements Initializable {

    @FXML
    private Button more;
    @FXML
    private Button close;
    @FXML
    private TextArea text;
    @FXML
    private Label title;

    public TextArea getText() {
        return text;
    }

    public void setText(String text) {
        this.text.setText(text);
    }

    public Label getTitle() {
        return title;
    }

    public void setTitle(String text) {
        this.title.setText(text);
    }

    @FXML
    public void closeAction(ActionEvent action) {
        // get a handle to the stage
        Stage stage = (Stage) close.getScene().getWindow();
        // do what you have to do
        stage.close();
    }

    @FXML
    public void moreAction(ActionEvent action) {
    }

    @FXML
    public void makeDocumentation(ActionEvent action) {
        this.title.setText("Documentation");
    }

    /**
     * Initializes the controller class.
     */
    @Override
    public void initialize(URL url, ResourceBundle rb) {
    }
}

Full Dialogue FXML

完整对话 FXML

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

<?import java.lang.*?>
<?import java.net.*?>
<?import java.util.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" padding="$x1" prefHeight="500.0" prefWidth="400.0" styleClass="mainFxmlClass" xmlns:fx="http://javafx.com/fxml" fx:controller="pdbpro.dialogues.DialogueController">
  <children>
    <GridPane alignment="CENTER" prefHeight="400.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
      <children>
        <Label fx:id="title" alignment="CENTER_LEFT" prefWidth="-1.0" styleClass="title" text="Title" underline="false" visible="true" GridPane.columnIndex="0" GridPane.rowIndex="0">
          <GridPane.margin>
            <Insets fx:id="x1" />
          </GridPane.margin>
        </Label>
        <TextArea fx:id="text" editable="false" focusTraversable="false" prefWidth="200.0" wrapText="true" GridPane.columnIndex="0" GridPane.rowIndex="1">
          <GridPane.margin>
            <Insets bottom="24.0" left="15.0" right="15.0" />
          </GridPane.margin>
        </TextArea>
        <ToolBar GridPane.columnIndex="0" GridPane.rowIndex="2">
          <items>
            <Button fx:id="more" mnemonicParsing="false" text="Find more" />
            <Button fx:id="close" mnemonicParsing="false" onAction="#closeAction" text="Close" />
          </items>
          <GridPane.margin>
            <Insets bottom="14.0" />
          </GridPane.margin>
        </ToolBar>
      </children>
      <columnConstraints>
        <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
      </columnConstraints>
      <padding>
        <Insets fx:id="x1" />
      </padding>
      <rowConstraints>
        <RowConstraints maxHeight="60.0" minHeight="60.0" prefHeight="60.0" valignment="CENTER" vgrow="NEVER" />
        <RowConstraints maxHeight="1.7976931348623157E308" minHeight="50.0" prefHeight="0.0" vgrow="ALWAYS" />
        <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
      </rowConstraints>
    </GridPane>
  </children>
  <stylesheets>
    <URL value="@dialogue.css" />
  </stylesheets>
</AnchorPane>

Full stack trace of error at these lines

这些行的完整错误堆栈跟踪

FXMLLoader loader = new FXMLLoader();
Parent root = loader.load(getClass().getResource("dialogues/dialogue.fxml"));
DialogueController dc = loader.getController();
dc.makeDocumentation(); //ERROR
Scene scene = new Scene(root);


java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
    at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1440)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:69)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:217)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:170)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:37)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:53)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:28)
    at javafx.event.Event.fireEvent(Event.java:171)
    at javafx.scene.control.MenuItem.fire(MenuItem.java:456)
    at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.doSelect(ContextMenuContent.java:1188)
    at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.handle(ContextMenuContent.java:1139)
    at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.handle(ContextMenuContent.java:1137)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:69)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:217)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:170)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:38)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:37)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:35)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:35)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:53)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:33)
    at javafx.event.Event.fireEvent(Event.java:171)
    at javafx.scene.Scene$MouseHandler.process(Scene.java:3324)
    at javafx.scene.Scene$MouseHandler.process(Scene.java:3164)
    at javafx.scene.Scene$MouseHandler.access00(Scene.java:3119)
    at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1559)
    at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2261)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:228)
    at com.sun.glass.ui.View.handleMouseEvent(View.java:528)
    at com.sun.glass.ui.View.notifyMouse(View.java:922)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.access0(WinApplication.java:29)
    at com.sun.glass.ui.win.WinApplication.run(WinApplication.java:73)
    at java.lang.Thread.run(Thread.java:722)
Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1435)
    ... 37 more
Caused by: java.lang.NullPointerException
    at pdbpro.MainController.documentationAction(MainController.java:82)
    ... 42 more

回答by Yarrgh

One way I can see is to make your controller implement initializable and implement the initialize method. The initialize method will be called automatically when the controller is created by the fxml loader. When the inititialize method is called all the fxml object declared should be initialized and ready to be customized.

我可以看到的一种方法是让您的控制器实现可初始化并实现 initialize 方法。当 fxml 加载器创建控制器时,将自动调用 initialize 方法。当调用 initialize 方法时,所有声明的 fxml 对象都应该被初始化并准备好进行定制。

[edit] After reading the docs for initializable, it says that if a method called initialize with no args is created that it will be called automatically with the fxml loader. So from what I understand, you don't need to implement initializable. Just create an initialize method with no args.

[编辑] 在阅读了可初始化文档后,它说如果创建了一个没有参数的名为 initialize 的方法,它将被 fxml 加载器自动调用。所以据我所知,你不需要实现可初始化。只需创建一个没有参数的初始化方法。

If needed, further info may be found in an introduction to fxml.

如果需要,可以在fxml 的介绍中找到更多信息。

回答by Uluk Biy

Try this:

试试这个:

root = (Parent) loader.load(getClass().getResource("dialogues/dialogue.fxml").openStream());
DialogueController dc = loader.getController();
dc.setTitle("title");
dc.setTextArea("text");
// and so on..
...
dialogue.show();

Assert that the DialogueController dc is not null. And assuming the "title" is a Label in fxml file with fx:id=titleLabel, it should be backed in your controller class like follows:

断言 DialogueController dc 不为空。假设“标题”是 fxml 文件中的一个标签fx:id=titleLabel,它应该在你的控制器类中支持,如下所示:

...
@FXML private Label titleLabel;
...
public void setTitle(String txt) {
    titleLabel.setText(txt);
}
...

回答by omelkova

I would suggest you to hide all FXML loading code to controller. For that it is possible to extend a Stage class:

我建议您将所有 FXML 加载代码隐藏到控制器。为此,可以扩展 Stage 类:

Controller:

控制器:

public class DialogueController extends Stage implements Initializable{
    @FXML private Button more;
    @FXML private Button close;
    @FXML private TextArea text;
    @FXML private Label title;

    public DialogueController(Parent parent){
        FXMLLoader loader = new FXMLLoader(getClass().getResource("dialogues/dialogue.fxml"));
        fxmlLoader.setController(this);
        super.setTitle("Documentation");
        try{
            setScene(new Scene((Parent) loader.load()));
        }catch(IOException e){
            e.printStackTrace();        
        }
        /*
         * Change values here
         */     
    }   
}

Call your controller:

调用您的控制器:

@FXML
private void documantationAction(ActionEvent action) throws IOException{
    DialogueController controller = new DialogueController(null);
    controller.show();
}