I'm trying to make an indicator light using a toggle button. It will "illuminate" when it's "Selected" value is true. And not "illuminate" when it's "Selected" value is false. I have added the regular button only to test the formatting of the visuals on the toggle button. In the actual program the "lights" will be controlled within other methods.
Problem is when I set the, toggleBtn.setSelected(true); it does not update the visuals. If I call toggleBtn.isSelected(); it returns true, so I know it is updating, just not the visual. If I "pre-select" the toggle button by clicking on it in the program before clicking the "Test" button, it will cycle to the off visuals. But it will not cycle back to the On visuals.
I have searched all over and I think it appears I need to add a listener however I'm not sure how that would help to update the visuals?
Following is the pertinent parts of the code. If you need more please let me know.
Controller
@FXML
private void LightsTest(ActionEvent event) throws InterruptedException {
System.out.println("Light illuminated");
toggleBtn.setSelected(true);
System.out.println("Light is Selected: " + toggleBtn.isSelected());
Thread.sleep(1000);
System.out.println("Light not illuminated");
toggleBtn.setSelected(false);
System.out.println("Light is Selected: " + toggleBtn.isSelected());
}
FXML
<AnchorPane id="mainPane" prefHeight="600.0" prefWidth="1024.0" stylesheets="@CSSFile.css" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml">
<children>
<ToggleButton id="Light" fx:id="toggleBtn" mnemonicParsing="false" styleClass="warningLights" text="LIGHT ON" />
<Button id="testBtn" fx:id="lightsBtn" layoutX="427.0" layoutY="30.0" mnemonicParsing="false" onAction="#LightsTest" prefHeight="49.0" prefWidth="106.0" text="TEST LIGHTS" />
</children>
</AnchorPane>
CSS
.warningLights {
-fx-background-color: linear-gradient(#132233 5%, #465566 50%, #132233 95%);
-fx-background-radius: 15px;
-fx-border-width: 5px;
-fx-border-radius: 15px 15px 15px 15px;
-fx-font-size: 18px;
-fx-font-weight: bold;
}
.warningLights:selected {
-fx-background-color: linear-gradient(#EE0000 5%, #FDA8A8 50%, #EE0000 95%);
-fx-effect: dropshadow(three-pass-box, black, 10, 0.0, 1, 5);
}
You are setting the selected
property to true
and then back to false
in the same method all in one go. This won't work as expected. When state changes the GUI won't reflect the changes until the next layout pulse. But the true
state won't be seen by the next layout pulse because said pulse will only occur some time after LightsTest
returns. In other words, modifying the state of nodes doesn't immediately update the GUI.
There's an auxiliary issue caused by your use of Thread.sleep
. This method is being called on the JavaFX Application Thread. While parked in Thread.sleep
the JavaFX Application Thread cannot do any other work and the GUI will freeze. Remember the Golden Rule of JavaFX: Never freeze, nor do long-running work on, the JavaFX Application Thread. This applies to many other UI frameworks as well—such as Swing/AWT and the Event Dispatch Thread.
Unrelated: Following proper Java naming conventions your method should be called lightsTest
, not LightsTest
.