Reference control by fx:id

Tags: , , ,



I have a calendar screen I have designed for class using JavaFX and Scene Builder. enter image description here

The part where I’ve placed the number is a label and the part that, currently, says “None”, is a button. I want to reference the value in the Label when I select the Button so that I can display the Appointments for the user for that day.

Is there a way to reference a control by by the FX:ID string name so that I can do this? The Label is called lblDayOfTheWeekxx and the button is called btnAppointmentxx, where xx is the value from 01 to 42.

This is what I have tried for changing the value. It’s just a test where I’m trying to turn the value of the first button to “DONE”.

    @FXML
void handleDayChosen(ActionEvent event) {
    try {
//            FXMLLoader loader = new FXMLLoader();
//            loader.setLocation(getClass().getResource("/Views/FormMain.fxml"));
//            Parent myView = loader.load();
//            Scene myScene = new Scene(myView);
//           Label lbl =  (Label) myScene.lookup("#lblDateOfMonth01");

//            Label myLblField = (Label)myView.FindControl("txtField" + 1);
//            lbl.setText("DONE");
        FXMLLoader loader = new FXMLLoader(getClass().getResource("/Views/FormMain.fxml"));
        Parent root = loader.load();
        Button foo = (Button)loader.getNamespace().get("lblAppointments01");

        foo.setText("DONE");
    } catch (Exception ex) {
        System.out.println(ex.getMessage());
    }
}

I’m new to Java so I don’t know what I’m doing wrong.

Thanks in advance,

Bill


This is what I finally came up with. I know it isn’t pretty but it works.

            GridPane gpCal = this.gpCalendar;
        for (int i = 1 ; i <= 7; i++) {
            int row = i * 2;
            for (int col = 1; col <= 7; col++) {
                int pos = ((i-1)*7)+col;
                lblDay[pos] = new Label();
                lblDay[pos].setText("");
                lblDay[pos].setPrefSize(100, 20);
                lblDay[pos].setText(String.valueOf(col) + ", " + String.valueOf(row));
                gpCal.add(lblDay[pos], col, row);
            }

            row++;
            for (int col = 0; col <= 6; col++) {
                int pos = ((i-1)*7)+col;
                btnAppts[pos] = new Button();
                btnAppts[pos].setText("");
                btnAppts[pos].setPrefSize(100, 100);
                btnAppts[pos].setText(String.valueOf(col) + ", " + String.valueOf(row));
                gpCal.add(btnAppts[pos], col, row);
            }

        } 

Now for the easy part of formatting the buttons and labels to kind of match below.

Thanks for the help,

Bill

Answer

UIs like this do not lend themselves at all well to FXML. It is usually much easier, and way less code, to create a UI like this using Java. That way you can create the button and label in a loop, and add a different event handler to each:

int numDays = 30 ; // in real life this comes from the month and year
GridPane calendarPane = ...; // can be a @FXML-injected variable if needed

for (int i = 1 ; i <= numDays ; i++) {
    Label dayLabel = new Label(Integer.toString(i));
    Button button = new Button("None");
    // set styles, etc
    int day = i ;
    button.setOnAction(e -> processButtonPress(button, dayLabel, day));
    VBox vbox = new VBox(dayLabel, button);
    int row = getRowForDay(i);
    int col = getColumnForDay(i);
    calendarPane.add(vbox, col, row);
}

// ...

private void handleDayChosen(Button button, Label label, int dayOfMonth) {
    // whatever you need here...
    label.setTextFill(Color.GREEN);
    button.setText("Done");
}

Obviously you can still use FXML for the surrounding UI if you want, and just put the loop above in the controller’s initialize() method. But this is clearly better than the 100+ lines of FXML plus 60 different variables in the controller to achieve the same thing.



Source: stackoverflow