简体   繁体   中英

Editing values/properties of an object of the controller class from another class

I have tried following the solution from here but without success: JavaFX Change label text from another class with controller

I am not sure if they want the same as I do.

So basically what I have is: FXMLDocumentController.java , FXMLDocument.xml, Operations.java , and Main.java . (I have some other classes that make the Arduino connection)

This is the start method that I have in my Main.java :

@Override
public void start(Stage primaryStage) throws IOException {

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

    Scene scene = new Scene(root);

    primaryStage.setTitle("This is the title");
    primaryStage.setScene(scene);
    primaryStage.show();

}

EDIT: Here's my Operations.java:

public class Operations {

private String mensagem, hora, dados;
private String [] msgSeparada, dadosSeparados;
private int origem, destino, tipoMensagem, comprimento;
private int [] estadoDosSensores;

public FiltrarMensagem(String mensagem) {
    //remove o primeiro e ultimo carater
    mensagem = mensagem.substring(1, mensagem.length()-2);
    this.mensagem = mensagem;
    System.out.printf("Mensagem Recebida: %s\n", mensagem);
    msgSeparada = this.mensagem.split(";");
    destino = Integer.valueOf(msgSeparada[0]);
    origem = Integer.valueOf(msgSeparada[1]);
    hora = msgSeparada[2];
    tipoMensagem = Integer.valueOf(msgSeparada[3]);
    comprimento = Integer.valueOf(msgSeparada[4]);
    dados = msgSeparada[5];
    dadosSeparados = dados.split(",");
}

public void imprimir() {
    System.out.printf("Origem: %d\n", origem);
    System.out.printf("Destino: %d\n", destino);
    System.out.printf("Hora: %s\n", hora);
    System.out.printf("Tipo de Mensagem: %d\n", tipoMensagem);
    System.out.printf("Comprimento: %d\n", comprimento);
    System.out.printf("Dados: %s\n\n", dados);
    if(Integer.valueOf(dadosSeparados[0]) == 1) {
                //change label value here
    }

}

}

To simplify, here's what my program does:

I have my controller class with 2 simple buttons that receive data from the serial port coming from an Arduino, and with the data received from the Arduino, I create an object of the class Operations so I can make the necessary changes depending on the data received from the Arduino, and what I would like to do is to change labels and all the objects available at the FXML file, but I am not able to do that. What is the simplest way to do it?

I've tried everything and with no success... So would really appreciate if someone could help me on this.

Simple solution for easy case

If you're instantiating your "other class" in response to a button press, ie in the controller, all you need to do is pass the new object a reference to the controller.

Ie

public class Controller {

    @FXML
    private Label label ;

    public void showMessage(String message) {
        label.setText(message);
    }

    @FXML
    private void handleButtonPress(ActionEvent event) {
        Operations ops = new Operations(this);
        ops.doYourThing();
    }
}

and then

public class Operations {

    private final Controller controller ;

    public Operations(Controller controller) {
        this.controller = controller ;
    }

    public void doYourThing() {
        // ...

        String someMessage = ... ;
        controller.showMessage(someMessage);

        // ...
    }
}

MVC approach

A slightly more general and robust solution is to use a MVC-approach, and create a model class. Your model class can use an observable StringProperty to keep the text to display. Share the model instance with the controller and with the service class ( Operations ). The controller can observe the property, so it can update the label whenever the property changes, and the service can update the property. This looks something like this:

public class Model {

    private final StringProperty message = new SimpleStringProperty(); 

    public StringProperty messageProperty() P{
        return message ;
    }

    public final String getMessage() {
        return messageProperty().get();
    }

    public final void setMessage(String message) {
        messageProperty().set(message);
    }

}
public class Main extends Application {

    @Override
    public void start(Stage primaryStage) {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
        Parent root = loader.load();
        Controller controller = loader.getController();

        Model model = new Model();
        controller.setModel(model);

        Scene scene = new Scene(root);

        primaryStage.setTitle("This is the title");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}
public class Controller {

    @FXML
    private Label label ;

    private Model model ;

    public void setModel(Model model) {
        this.model = model ;
        model.messageProperty().addListener((obs, oldMessage, newMessage) ->
            label.setText(newMessage));
    }

    @FXML
    private void handleButtonPress(ActionEvent event) {
        Operations ops = new Operations(model);
        ops.doYourThing();
    }
}

And finally

public class Operations {

    private final Model model ;

    public Operations(Model model) {
        this.model = model ;
    }

    public void doYourThing() {
        // ...

        String someMessage = ... ;
        model.setMessage(message);

        // ...
    }
}

The benefits to this (slightly more complex) approach are:

  1. You remove any coupling between your "service" class and the controller, so the service is really independent of the UI
  2. This now works if the service is created elsewhere, as you have access to the model in a wider scope (it's created in the Main class, which is the entry point to the application).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM