Just for background, I used to code a bit years ago doing web design stuff, but for all intents and purposes I am just getting my feet wet with Java (like literally 3 days in), so try and take it easy on me! This whole program just tracks clicks, saves and loads them, and that's basically all it will ever do. It's just an exercise and it has proven to be plenty for me to chew on for the last several days.
The goal is to get the label in Click.fxml to change whenever the click count increases. I've got the logic working correctly which I've verified through the console, but I can't seem to get this label to update when the count value increases. I already know I've overlooked or missed something incredibly simple or otherwise just have a fundamental misunderstanding of how any of this works!
Here's what I have at the moment, based on reading through lots of stack questions and documentation:
Click.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.net.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<VBox
xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml"
fx:controller="application.ViewModel">
<Button text="Click 1x" onAction="#clicked1x" />
<Button text="Click 5x" onAction="#clicked5x" />
<Button text="Test" onAction="#test" />
<Label fx:id="currentTotalLabel"/>
</VBox>
ViewModel.java
package application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
public class ViewModel {
public Counter counter = new Counter();
public Label currentTotalLabel;
public ObservableValue<? extends String> totalText =
new SimpleStringProperty(this, "rand", getCurrentTotalText());
public void initialize() {
currentTotalLabel.textProperty().bind(totalText);
totalText.addListener(new ChangeListener<String>() {
public void changed(ObservableValue<? extends String> observable,
String oldValue, String newValue) {
System.out.println("changed: " + oldValue + " -> " + newValue);
}
});
}
@FXML
private void clicked1x(ActionEvent event) {
counter.setTotal(1);
System.out.println("Clicked 1x; " + getCurrentTotalText());
}
@FXML
private void clicked5x(ActionEvent event) {
counter.setTotal(5);
System.out.println("Clicked 5x; " + getCurrentTotalText());
}
@FXML
public String getCurrentTotalText() {
String currentTotalText = counter.getTotal().getValue() + " total clicks!";
return currentTotalText;
}
@FXML
private void test(ActionEvent event) {
System.out.println(getCurrentTotalText());
}
}
I've tried a bunch of other ways to approach this, and I purposely want to achieve this using binding. I just don't know exactly where I've gone wrong.
You can bind a label textProperty
to a counting integer property using asString()
to get a string binding.
Label label = new Label();
IntegerProperty count = new SimpleIntegerProperty(0);
label.textProperty().bind(
count.asString()
);
Whenever the count
property is changed, the text property of the label
will change to the string representation of the count value.
Example Code
import javafx.application.Platform;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.scene.control.Label;
public class BoundLabel {
public static void main(String[] args) {
Platform.startup(BoundLabel::runTest);
Platform.exit();
}
private static void runTest() {
Label label = new Label();
IntegerProperty count = new SimpleIntegerProperty(0);
label.textProperty().bind(
count.asString()
);
label.textProperty().subscribe(labelText ->
System.out.println(labelText)
);
for (int i = 0; i < 5; i++) {
count.set(count.getValue() + 1);
}
}
}
Outputs
0
1
2
3
4
5