-1

i'm new to Javafx and in generell GUI-programming. I'm working on an application which e.g. Labels need to be updated, as soons as there are any changes on the variable. I already use Properties and Bindings, but the change is only visible if i close an reopen the window. To be clearer, i don't mean change a Label if the User writes in a Textfiel, with that i have no problems. But with Labels that holds Integer or Strings and don't really have a trigger.

So my generell question is: How do i update something on the application, as soon as something changes. I recreated an simple example, so that maybe you guys can undertand what I want to ask (not a native speaker, sorry), but without the option to close an reopen the window.

Main:

 public class Test extends Application{
      public static void main(String[] args) {
        launch(args);
        
    }
      @Override
     public void start(Stage primaryStage) throws Exception {
        Stage window = primaryStage;
        window.setTitle("Configuration");
        
        
        FlowPane numberOfDirPane = new FlowPane();
        Label dirLabel = new Label("Number of Directories: ");
        Label numberOfDirLabel = new Label("");
        
        numberOfDirPane.getChildren().addAll(dirLabel, new Label (Integer.toString(DataModel.number.get())));
        numberOfDirPane.setAlignment(Pos.CENTER);

        
        
        FlowPane editDir = new FlowPane();
        Label editLabel = new Label("Edit Number of Directories: ");
        TextField numberDirText = new TextField();
        numberDirText.setMaxWidth(50);
        Button editDirNumberButton = new Button("Confirm");
       
        editDirNumberButton.setOnAction(e -> {
            DataModel.getNumber(Integer.parseInt(numberDirText.getText()));
 
            numberOfDirLabel.textProperty().bind(DataModel.number.asString());
           
        });
        
        

        editDir.getChildren().addAll(editLabel, numberDirText, editDirNumberButton);
        editDir.setAlignment(Pos.CENTER);
        editDir.setHgap(40);
                
        
        
        FlowPane buttons = new FlowPane();
        Button confirmEditButton = new Button("Confirm");
  
        Button closeButton = new Button("Close");
        closeButton.setOnAction(e -> window.close());
        
        buttons.getChildren().addAll(confirmEditButton, closeButton);
        buttons.setAlignment(Pos.CENTER);
        buttons.setHgap(20);
        
        
        
        VBox layout = new VBox(20);
        layout.getChildren().addAll(numberOfDirPane, editDir, buttons);
        layout.setAlignment(Pos.CENTER);
        Scene scene = new Scene(layout, 500, 300);
        window.setScene(scene);
        window.show();
    }
 }

DataModel:

public class DataModel {
    public static IntegerProperty number = new SimpleIntegerProperty(0);
                
    public static void getNumber(int number) {
        DataModel.number.set(number);
        System.out.println("DataModel " + number);     
    }
}
c0der
  • 18,467
  • 6
  • 33
  • 65
  • 1
    One obious thing is do you really want to keep binding every time an action is triggered? `numberOfDirLabel.textProperty().bind(DataModel.number.asString());` – SedJ601 Nov 11 '20 at 15:05
  • 1
    `DataModel.getNumber` looks like it should be a setter. Also, I believe you should have the method `getNumberProperty`. That will allow you to create your bindings. – SedJ601 Nov 11 '20 at 15:07
  • `DataModel.number.set(number);` is very bad practice in `JavaFX` and probably should be avoided. I would suggest you study @Jame_D answer [here](https://stackoverflow.com/questions/32342864/applying-mvc-with-javafx). – SedJ601 Nov 11 '20 at 15:10
  • 1
    whatever you do, don't use static scope! And don't use implement getters with side-effect .. (which probably is what @Sedrick already pointed out :) Overall, your code looks like you need to work through a couple of tutorial on java language basics plus javafx basics ... – kleopatra Nov 11 '20 at 15:55
  • The reason it's not working is that you never actually add `numberOfDirLabel` to the scene. – James_D Nov 11 '20 at 16:46
  • @Sedrick Thanks, i will read that thread –  Nov 11 '20 at 20:06
  • @James_D yees, i forgot that but I looked it up in my original Code and i definitly add that. And in case you ask, i can't post the original code because there are too many dependencies and i propably cannot explain it that good so you guys can understand my problem.. But in generell: How can i update the display as soon as it changes? Without closing and reopening the window? –  Nov 11 '20 at 20:11
  • 1
    The label *does* update as soon as the value changes. You don't see it change, because you haven't added it to the scene. – James_D Nov 11 '20 at 20:12

1 Answers1

1

Please review the comments to follow the changes made to the code. To run copy the entire code into Test.java and run :

import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Test extends Application{
    public static void main(String[] args) {
        launch(args);
    }
    @Override
    public void start(Stage primaryStage) throws Exception {

        Stage window = primaryStage;
        window.setTitle("Configuration");

        FlowPane numberOfDirPane = new FlowPane();
        Label dirLabel = new Label("Number of Directories: ");

        //construct a DataModel
        DataModel dataModel = new DataModel();

        //in the original code this label was constructed but never added to a panel
        Label numberOfDirLabel = new Label("");
        //bind label to the data model
        numberOfDirLabel.textProperty().bind( dataModel.numberProperty().asString());

        //add numberOfDirLabel to the panel
        numberOfDirPane.getChildren().addAll(dirLabel, numberOfDirLabel);
        numberOfDirPane.setAlignment(Pos.CENTER);

        FlowPane editDir = new FlowPane();
        Label editLabel = new Label("Edit Number of Directories: ");
        TextField numberDirText = new TextField();
        numberDirText.setMaxWidth(50);
        Button editDirNumberButton = new Button("Confirm");

        editDirNumberButton.setOnAction(e -> {
            dataModel.setNumber(Integer.parseInt(numberDirText.getText()));
        });

        editDir.getChildren().addAll(editLabel, numberDirText, editDirNumberButton);
        editDir.setAlignment(Pos.CENTER);
        editDir.setHgap(40);
        //to demonstrate the problem the following Flowpane is not needed
        //and should be removed. see https://stackoverflow.com/help/minimal-reproducible-example
        FlowPane buttons = new FlowPane();
        Button confirmEditButton = new Button("Confirm");

        Button closeButton = new Button("Close");
        closeButton.setOnAction(e -> window.close());

        buttons.getChildren().addAll(confirmEditButton, closeButton);
        buttons.setAlignment(Pos.CENTER);
        buttons.setHgap(20);

        VBox layout = new VBox(20);
        layout.getChildren().addAll(numberOfDirPane, editDir, buttons);
        layout.setAlignment(Pos.CENTER);
        Scene scene = new Scene(layout, 500, 300);
        window.setScene(scene);
        window.show();
    }
}

class DataModel {

    //there is no need to use static fieilds and methods here
    private final IntegerProperty numberProperty = new SimpleIntegerProperty(0);

    public  void setNumber(int number) {
        numberProperty.set(number);
    }

    //add a getter
    public IntegerProperty numberProperty() {
        return numberProperty;
    }
}
c0der
  • 18,467
  • 6
  • 33
  • 65