Как обновить SceneBuilder GUI при изменении другого объекта в программе моделирования? - PullRequest
1 голос
/ 12 июля 2020

Я программирую приложение-симулятор на Java. Есть 3 разных класса. Некоторые изменения в этих классах должны изменить TextField в GUI (сделано SceneBuilder). Нажатие кнопки в gui, должно менять объекты в классах. Я сделал GUI с SceneBuilder, я знаю, как использовать класс контроллера. Есть ли способ использовать класс контроллера для FXML в классе объекта для изменения текста в 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);
        }   
    }
}

Второй вопрос, могу ли я запрограммировать изменение объекта в классе управления, когда я нажимаю кнопку? Примерно так:

@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 текстовых поля, которые должны изменять состояние симулятора.

ОБНОВЛЕНИЕ: У меня есть город и движущиеся люди. Когда человек заражен, Watchman должен видеть в текстовом поле позицию человека. У меня f xml с кнопками и текстовыми полями. Я знаю, что у класса Watchman должен быть Controler от f xml. Я получаю Controler с

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

После этого я отправляю Controler в класс Watchman с помощью

city.getWatchman().setControler(loader.getController());

В классе Watchman я пытаюсь отредактировать 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);
        }   
    }
}

Теперь я получил ошибку

Вызвано: java .lang.ClassCastException: класс javafx.scene.layout.AnchorPane не может быть преобразован в класс javafx.f xml .FXMLLoader (javafx .scene.layout.AnchorPane находится в модуле javafx.graphics загрузчика app; javafx.f xml .FXMLLoader находится в модуле javafx.f xml загрузчика app)

ОБНОВЛЕНИЕ, если ответ ниже для вас сложен ... В класс контроллера вы можете помещать объекты, которые вы будете контролировать. В моем случае это примерно так:

Person infectedPerson;
Ambulance ambulance;

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

В другом классе я помещаю этот код, чтобы установить тот же контроллер для f xml и класса, который будет использовать их оба

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

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

В основном классе вы можете указать:

    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);

Я постараюсь объяснить последнюю часть кода. Сначала вы создаете FXMLLoader с файлом f xml, в котором определен контроллер. Затем вы его загружаете. (если вы не вызываете load (), это не сработает). После этого вы должны вызвать getController, чтобы в вашей функции был такой же контроллер, и вы можете вызывать функции контроллера извне для управления своей частью GUI.

1 Ответ

1 голос
/ 18 июля 2020

Вот как вы можете привязать текст Object к Label или TextField, чтобы управлять GUI, манипулируя объектом, и наоборот.

Обратите внимание, что этот ответ сосредоточен на вашем вопросе, но не дает вам решения для копирования и вставки. Для этого я поместил весь проект (включая pom. xml) в репозиторий на моем GitHub на случай, если вы захотите его клонировать и поиграть.

Я использовал модульный проект с Maven , вы можете найти различные способы настройки вашей среды здесь .

Приложение: (основной класс)

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) с TextField и Label textProperty.

Обратите внимание, что привязка здесь однонаправленная, что означает, что только manipulatedText влияет на TextField и Label, а не наоборот. Чтобы выполнить sh, которое вы можете использовать bindBidirectional.

Теперь нажатие manipulateWatchmanBTN изменяет только текст Watchman manipulatedText - Это был ответ на ваш второй вопрос . Поскольку мы привязали к нему наш GUI, элементы GUI, которые мы создали с помощью SceneBuilder, также меняют - , и это ответ на ваш первый вопрос .

Не стесняйтесь настраивать его, чтобы ваши конкретные c потребности.

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