在模拟程序中更改不同对象时如何更新 Scene Builder GUI?

How to update SceneBuilder GUI when change different object in simulaton program?

我正在 Java 中编写模拟器应用程序。有 3 种不同的 classes。 classes 中的某些更改必须更改 GUI 中的 TextField(SceneBuilder 制作)。在 gui 中单击按钮,必须在 classes 中更改对象。我用 SceneBuilder 制作了 GUI,我知道如何使用控制器 class。 有什么方法可以使用控制器 class for FXML in object class 来更改 TextField 中的文本吗?像这样:

@Override
public void run() {
    while (0 != 1) {
        if (!stack.isEmpty())
            controls.settfAI("INFECTED"); //controls is FXML controller // settfAI is id of text field
        try {
            sleep(3000);
        } catch (InterruptedException e) {
            CCLogger.cclogger(Watchman.class.getName(), Level.INFO, e);
        }   
    }
}

第二个问题,当我点击按钮时,我可以编程改变控件中的对象class吗?像这样:

@FXML
Button btnOne; //btnOne is id in SceneBuilder file
//...
// AmbulanceCar ambulanceCar=new AmbulanceCar();
public void clicked() {
    ambulanceCar.go(); // send ambulance car in some location 
}

我的程序有很多按钮和 3 个必须更改模拟器状态的 TextField。

更新: 我有城市和移动的人。当人被感染时,Watchman 必须在 TextField 中看到人的位置。我有带有按钮和文本字段的 fxml。我知道 Watchman class 必须有来自 fxml 的 Controler。我得到控制器

        Parent watchBtns = FXMLLoader.load(getClass().getResource("ControlGUI.fxml"));
    URL contronLinkUrl=Paths.get("/ControlGUI.fxml").toUri().toURL();
    FXMLLoader loader=FXMLLoader.load(contronLinkUrl);

之后,我用

将Controler发送给Watchmanclass
city.getWatchman().setControler(loader.getController());

在 Watchman class 中,我尝试使用以下代码编辑 TextField:

    public void setControler(ControlerControlGUI controlGUI)
{
    controlerControlGUI=controlGUI;
    System.out.println("Controler set!");
}

@Override
public void run()
{
    System.out.println("Watchman started!");
    while(0!=1)
    {
        try {
        if(!stack.isEmpty())
            { 
              controlerControlGUI.settfAI("INFECTED");
            }

            sleep(3000);
        } catch (InterruptedException e) {
            CCLogger.cclogger(Watchman.class.getName(), Level.INFO, e);
        }   
    }
}

现在我得到了错误

Caused by: java.lang.ClassCastException: class javafx.scene.layout.AnchorPane cannot be cast to class javafx.fxml.FXMLLoader (javafx.scene.layout.AnchorPane is in module javafx.graphics of loader 'app'; javafx.fxml.FXMLLoader is in module javafx.fxml of loader 'app')

更新,如果下面的答案对你来说很复杂... 在控制器 class 中,您可以放置​​您要控制的对象。在我的例子中是这样的:

Person infectedPerson;
Ambulance ambulance;

//call in main function
public void setInfectedInfo(Person person,Ambulance amb)
{
    infectedPerson=person;
    ambulance=amb;
}

在其他 class 中,我将此代码用于为 fxml 和 class 设置相同的控制器,这将同时使用它们

Stack<Alarm> stack= new Stack<>();
Vector<Ambulance> ambulances=new Vector<>();
ControlerControlGUI controlerControlGUI;

public void setControler(ControlerControlGUI controlGUI)
{
    controlerControlGUI=controlGUI;
}

在 main class 中你可以输入:

    FXMLLoader loader=new 
       FXMLLoader(getClass().getResource("ControlGUI.fxml"));
    Parent watchBtns=loader.load();
    city.getWatchman().setControler(loader.getController());
    watchBtns.setLayoutX(840);
    watchBtns.setLayoutY(100);
    groupCity.getChildren().add(watchBtns);

我将尝试解释最后的代码部分。首先,您使用定义了控制器的 fxml 文件制作 FXMLLoader。然后你加载它。 (如果你不调用 load() 这将不起作用)。之后,您必须调用 getController 以在您的函数中拥有相同的控制器,并且您可以从外部调用控制器函数来控制您的 GUI 部分。

这里介绍了如何将 Object 的文本绑定到 LabelTextField 以通过操作对象来操作 GUI,反之亦然。

请注意,此答案侧重于您的问题,但并未为您提供复制和粘贴解决方案。为此,我将整个项目(包括 pom.xml)推送到 repo on my GitHub,以防你想克隆它并玩转它。

我使用了 Maven, you can find various ways to set up your environment here 的模块化项目。

应用程序:(主要class)

package com.broudy;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.IOException;

/**
 * JavaFX App
 */
public class App extends Application {

    private static Scene scene;

    @Override
    public void start(Stage stage) throws IOException {
        scene = new Scene(loadFXML("primary"));
        stage.setScene(scene);
        stage.show();
    }

    static void setRoot(String fxml) throws IOException {
        scene.setRoot(loadFXML(fxml));
    }

    private static Parent loadFXML(String fxml) throws IOException {
        FXMLLoader fxmlLoader = new FXMLLoader(App.class.getResource(fxml + ".fxml"));
        return fxmlLoader.load();
    }

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

}

守望者:

package com.broudy;

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class Watchman {

  private StringProperty manipulatedText;

  public Watchman() {
    this.manipulatedText = new SimpleStringProperty("howdy!");
  }

  public String getManipulatedText() {
    return manipulatedText.get();
  }

  public StringProperty manipulatedTextProperty() {
    return manipulatedText;
  }

  public void setManipulatedText(String manipulatedText) {
    this.manipulatedText.set(manipulatedText);
  }
  
}

主控制器:

package com.broudy;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;

public class PrimaryController {

  @FXML
  private Label manipulatedLBL;

  @FXML
  private Button primaryButton;

  @FXML
  private TextField manipulatedTF;

  @FXML
  private Button manipulateWatchmanBTN;

  private int i = 0;

  @FXML
  private void initialize() {
    List<String> texts = new ArrayList<>();
    texts.add("Hey! It works... Click again...");
    texts.add("Again...");
    texts.add("And again...");
    texts.add("Wohooo");
    texts.add("Yipeeeeeee!");
    texts.add("Notice: ...");
    texts.add("The text is changed in Watchman class but these change as well...");

    Watchman watchman = new Watchman();
    manipulatedTF.textProperty().bind(watchman.manipulatedTextProperty());
    manipulatedLBL.textProperty().bind(watchman.manipulatedTextProperty());

    //    This is another acceptable way of assigning actions to buttons, etc.
    manipulateWatchmanBTN.setOnAction(click -> {
      watchman.setManipulatedText(texts.get(i++));
      // This is just to reset the text
      if (i >= texts.size()) {
        i = 0;
      }
    });
  }
  
  @FXML
  private void switchToSecondary() throws IOException {
    App.setRoot("secondary");
  }
}

简要说明:

PrimaryController 创建了一个 Watchman 实例并将其 textProperty (manipulatedText) 绑定到 TextFieldLabeltextProperty

请注意,这里的绑定是单向的,这意味着只有 manipulatedText 会影响 TextFieldLabel 而不是相反。为此,您可以使用 bindBidirectional.

现在,单击 manipulateWatchmanBTN 只会更改 WatchmanmanipulatedText 的文本 - 这是对您第二个问题的回答 .因为我们将 GUI 绑定到它,所以我们使用 SceneBuilder 创建的 GUI 元素也会发生变化 - 这是对您第一个问题的回答

随时根据您的具体需要进行调整。