在 运行 FXML 中的下一个函数之前停止 X 秒(使用 SCENEBUILDER)
stop for X seconds before running next function in JAVA FXML (using SCENEBUILDER)
我使用 Scenebuilder 在我的 GUI 中放置了几个形状(我的项目的简化版本)。我希望形状改变颜色,但在改变颜色之间等待 2 秒。我希望在按下按钮后在我的控制器 class 中发生这些更改。
Circle1.setFill(YELLOW)
Wait(2 seconds)
Circle2.setFill(BLUE)
我不知道该怎么做。我在网上阅读过有关线程的内容,但我并不真正了解如何从我的 Main 到我的 Controller class 实现它。另外,我真的无法在网上找到任何示例。我的主要 class 看起来像:
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
BorderPane root = (BorderPane)FXMLLoader.load(getClass().getResource("File.fxml"));
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
}
请帮忙。另外,如果你能提供一个例子,那将有助于我理解,因为我在网上找不到一个例子。
我认为通过一个例子回答这个问题是最简单的。因此,我创建了一个小型交通灯应用程序,因为它允许我使用 Circle
和类似于您的问题的时间序列,同时对所有人来说都是一个熟悉的概念。
我将使用 java.util.Timer
和 java.util.TimerTask
来处理灯光序列。您可以选择在 JavaFX 中使用一些动画/时间线,但我认为这对于此类任务来说太过分了。
我包含了这个项目中使用的三个文件:
FXMLTrafficLight.fxml
- 定义我的 FXML 布局
FXMLTrafficLightController.java
- 我的 FXML 控制器
TrafficLightApplication.java
- 为了完整起见,我的 Application
子类,这只是样板。
FXMLTrafficLight.fxml
不是花哨的布局,只是一个 VBox
三个圆圈 redLight
、amberLight
和 greenLight
,加上两个 Button
个对象 startLights
和 stopLights
用于启动和停止计时器。
<VBox fx:id="root" id="VBox" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxtimer.FXMLTrafficLightController">
<children>
<Circle fx:id="redLight" radius="100"></Circle>
<Circle fx:id="amberLight" radius="100"></Circle>
<Circle fx:id="greenLight" radius="100"></Circle>
<Button fx:id="startLights" text="Start Lights" onAction="#startLights"></Button>
<Button fx:id="stopLights" text="Start Lights" onAction="#stopLights"></Button>
</children>
</VBox>
FXMLTrafficLightController.java
为了简单起见,我在控制器中包含了 model/state。灯是红色/琥珀色/绿色由 boolean
标志决定。初始状态在 initialize()
方法中设置,并通过调用 updateState()
.
进行更新
当调用 startLights(ActionEvent)
时(startLights
的 EventHandler
),将使用首先调用 updateState()
在由 Timer
创建的线程上,然后调用 updateLights()
,它使用 Platform.runLater(Runnable)
.
根据 JavaFX 应用程序线程上的当前状态更改灯光的颜色
注意:TimerTask
本身不会在 JavaFX 应用程序线程上 运行,因此需要使用 Platform.runLater(Runnable)
来更新 GUI。
调用stopLights(ActionEvent)
时,会取消Timer
。
请注意,startLights(ActionEvent)
和 stopLights(ActionEvent)
也会切换在界面上启用哪些 Button
对象。
public class FXMLTrafficLightController implements Initializable {
@FXML
private Circle redLight;
@FXML
private Circle amberLight;
@FXML
private Circle greenLight;
@FXML
private Button startLights;
@FXML
private Button stopLights;
private Timer timer;
private static final int DELAY = 2000; // ms
private boolean red, amber, green;
@Override
public void initialize(URL url, ResourceBundle rb) {
red = true;
amber = false;
green = false;
stopLights.setDisable(true);
updateLights();
}
@FXML
private void startLights(ActionEvent e) {
toggleButtons();
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
// Not run on the JavaFX Application Thread!
updateState();
// Using Platform.runLater(Runnable) to ensure updateLights()
// is run on the JavaFX Application Thread
Platform.runLater(new Runnable() {
@Override
public void run() {
updateLights();
}
});
}
}, 0, DELAY); // no initial delay, trigger again every 2000 ms (DELAY)
}
@FXML
private void stopLights(ActionEvent e) {
toggleButtons();
timer.cancel();
}
private void toggleButtons() {
startLights.setDisable(!startLights.isDisable());
stopLights.setDisable(!stopLights.isDisable());
}
private void updateState() {
if (red && !amber && !green) {
amber = true;
} else if (red && amber && !green) {
red = false;
amber = false;
green = true;
} else if (!red && !amber && green) {
green = false;
amber = true;
} else {
red = true;
amber = false;
green = false;
}
}
private void updateLights() {
redLight.setFill(red ? Color.RED : Color.GREY);
amberLight.setFill(amber ? Color.ORANGE : Color.GREY);
greenLight.setFill(green ? Color.GREEN : Color.GREY);
}
}
TrafficLightApplication.java
为了完整性...只是更改了文件名的标准样板。
public class TrafficLightApplication extends Application {
@Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLTrafficLight.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
我使用 Scenebuilder 在我的 GUI 中放置了几个形状(我的项目的简化版本)。我希望形状改变颜色,但在改变颜色之间等待 2 秒。我希望在按下按钮后在我的控制器 class 中发生这些更改。
Circle1.setFill(YELLOW)
Wait(2 seconds)
Circle2.setFill(BLUE)
我不知道该怎么做。我在网上阅读过有关线程的内容,但我并不真正了解如何从我的 Main 到我的 Controller class 实现它。另外,我真的无法在网上找到任何示例。我的主要 class 看起来像:
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
BorderPane root = (BorderPane)FXMLLoader.load(getClass().getResource("File.fxml"));
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
}
请帮忙。另外,如果你能提供一个例子,那将有助于我理解,因为我在网上找不到一个例子。
我认为通过一个例子回答这个问题是最简单的。因此,我创建了一个小型交通灯应用程序,因为它允许我使用 Circle
和类似于您的问题的时间序列,同时对所有人来说都是一个熟悉的概念。
我将使用 java.util.Timer
和 java.util.TimerTask
来处理灯光序列。您可以选择在 JavaFX 中使用一些动画/时间线,但我认为这对于此类任务来说太过分了。
我包含了这个项目中使用的三个文件:
FXMLTrafficLight.fxml
- 定义我的 FXML 布局FXMLTrafficLightController.java
- 我的 FXML 控制器TrafficLightApplication.java
- 为了完整起见,我的Application
子类,这只是样板。
FXMLTrafficLight.fxml
不是花哨的布局,只是一个 VBox
三个圆圈 redLight
、amberLight
和 greenLight
,加上两个 Button
个对象 startLights
和 stopLights
用于启动和停止计时器。
<VBox fx:id="root" id="VBox" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxtimer.FXMLTrafficLightController">
<children>
<Circle fx:id="redLight" radius="100"></Circle>
<Circle fx:id="amberLight" radius="100"></Circle>
<Circle fx:id="greenLight" radius="100"></Circle>
<Button fx:id="startLights" text="Start Lights" onAction="#startLights"></Button>
<Button fx:id="stopLights" text="Start Lights" onAction="#stopLights"></Button>
</children>
</VBox>
FXMLTrafficLightController.java
为了简单起见,我在控制器中包含了 model/state。灯是红色/琥珀色/绿色由 boolean
标志决定。初始状态在 initialize()
方法中设置,并通过调用 updateState()
.
当调用 startLights(ActionEvent)
时(startLights
的 EventHandler
),将使用首先调用 updateState()
在由 Timer
创建的线程上,然后调用 updateLights()
,它使用 Platform.runLater(Runnable)
.
注意:TimerTask
本身不会在 JavaFX 应用程序线程上 运行,因此需要使用 Platform.runLater(Runnable)
来更新 GUI。
调用stopLights(ActionEvent)
时,会取消Timer
。
请注意,startLights(ActionEvent)
和 stopLights(ActionEvent)
也会切换在界面上启用哪些 Button
对象。
public class FXMLTrafficLightController implements Initializable {
@FXML
private Circle redLight;
@FXML
private Circle amberLight;
@FXML
private Circle greenLight;
@FXML
private Button startLights;
@FXML
private Button stopLights;
private Timer timer;
private static final int DELAY = 2000; // ms
private boolean red, amber, green;
@Override
public void initialize(URL url, ResourceBundle rb) {
red = true;
amber = false;
green = false;
stopLights.setDisable(true);
updateLights();
}
@FXML
private void startLights(ActionEvent e) {
toggleButtons();
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
// Not run on the JavaFX Application Thread!
updateState();
// Using Platform.runLater(Runnable) to ensure updateLights()
// is run on the JavaFX Application Thread
Platform.runLater(new Runnable() {
@Override
public void run() {
updateLights();
}
});
}
}, 0, DELAY); // no initial delay, trigger again every 2000 ms (DELAY)
}
@FXML
private void stopLights(ActionEvent e) {
toggleButtons();
timer.cancel();
}
private void toggleButtons() {
startLights.setDisable(!startLights.isDisable());
stopLights.setDisable(!stopLights.isDisable());
}
private void updateState() {
if (red && !amber && !green) {
amber = true;
} else if (red && amber && !green) {
red = false;
amber = false;
green = true;
} else if (!red && !amber && green) {
green = false;
amber = true;
} else {
red = true;
amber = false;
green = false;
}
}
private void updateLights() {
redLight.setFill(red ? Color.RED : Color.GREY);
amberLight.setFill(amber ? Color.ORANGE : Color.GREY);
greenLight.setFill(green ? Color.GREEN : Color.GREY);
}
}
TrafficLightApplication.java
为了完整性...只是更改了文件名的标准样板。
public class TrafficLightApplication extends Application {
@Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLTrafficLight.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}