使用循环从事件方法内部在事件方法中连续更新我的布局元素
To update my layout elements continuously in an event method from inside the event method using loops
我正在尝试构建一个模拟秒表。有一个按钮,当我单击时,秒表开始以秒为单位计数。
请注意,此代码运行良好(技术上),但就我基于 "java language" 的逻辑 or/and 我基于思维的逻辑而言存在一些问题。我也知道我的秒表会在几毫秒内出现一些边际误差。有两个打印语句可以检查我的逻辑。请注意,我有一些 C 编码经验,但对此并不陌生。 编辑:平台是javaFX
现在,我在使用这段代码时遇到了 3 个问题。
技术写的三个问题:
1- 第二个打印语句的输出与第一个相同。即,我的 IF 语句不起作用,因为 temp + 1 仍然等于当前秒数,尽管如果我们考虑到它们之间的代码行执行得更快这一事实,这是不可能的。 更新:此 (1) 已解决。
2- 忽略问题 (1),我的图像没有旋转,尽管自执行 IF 语句以来它应该旋转。请注意,我正在使用 stackpane 并将该图像添加到我的布局中,但它只是停留在 0 度并且没有做任何事情。
3- 即使我等待了太多时间,While 循环本身也不工作。我不确定在事件处理方法中是否使用 "okay" 或不使用 while 循环。
三题结构写法:
1- N/A
2- 我是否可以使用循环而不是使用按钮或其他方式从 even 方法内部在事件方法中连续更新我的布局元素?
3- 同 (2)
btn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
int temp = 0;
Calendar calendar = Calendar.getInstance();
System.out.println("Seconds in current minute = " + calendar.get(Calendar.SECOND));
temp = calendar.get(Calendar.SECOND);
int temp2 = temp + 60;
int counter = 1;
do {
System.out.println("Seconds in current minute = " + calendar.get(Calendar.SECOND));
if ((temp + 1) == calendar.get(Calendar.SECOND)) {
System.out.println("Seconds in current minute = " + calendar.get(Calendar.SECOND));
imageHolder2.rotateProperty().set(6.0 * counter);
counter++;
temp = calendar.get(Calendar.SECOND);
}
} while (temp2 != (calendar.get(Calendar.SECOND) + 60));
}
});
1) 我想你只是看到了第一个 System.out.println(...)
(从循环之前)和循环中的第一个,它们将产生相同的输出(除了非常罕见的(几次出现)每百万次运行?)在执行中间三行代码期间的秒数 "tick over" 的情况)。
2) 这才是真正的问题。您的循环在 FX 应用程序线程中是 运行(忙碌)(因为它是由事件处理程序调用的)。这是用于更新 UI 和处理事件的同一个线程。因为你让这个线程一直忙,所以在你的循环完成之前它没有任何机会更新 UI 。您需要在后台线程中执行此循环,并在 FX 应用程序线程上安排 UI 更新,或者(更容易)使用动画 API 来执行此操作。
3) 你的逻辑有很多错误。 (1) 在开始循环之前分配 calendar
,并且从不更新它;所以它总是代表处理程序启动的瞬间。 (2) 你把temp2
赋值为seconds + 60
然后你的循环条件是temp2 != seconds + 60
,这显然是假的,所以循环退出。即使您在循环迭代中更新 calendar
,seconds
字段在循环的第一次迭代中发生变化的可能性极小,因此您几乎肯定会立即退出循环。 (3) 如果更新calendar
,seconds
字段将始终为0到59(含)之间的值,即它将"wrap"为60。temp2
将始终为至少 60,所以一旦你修复了错误 (1) 和 (2),你的循环将永远不会退出... (4) if (temp + 1 == calendar.get(Calendar.SECONDS))
将在分钟结束时失败,因为 60 != 0
,所以你的一旦发生这种情况,迭代就会停止。
您可以使用 Timeline
来做到这一点:
@Override
public void handle(ActionEvent event) {
Timeline timeline = new Timeline(
// key frame that updates rotation on each second:
new KeyFrame(Duration.seconds(1), e -> {
imageHolder2.setRotate(imageHolder2.getRotate() + 6);
System.out.println("Seconds in current minute = " + Calendar.getInstance().get(Calendar.SECOND));
})
);
// repeat 60 times:
timeline.setCycleCount(60);
timeline.play();
}
如果您想使用您的原始代码,您需要将其包装在后台线程中,并在 FX 应用程序线程上安排 UI 更新。如上所述,您的代码中还有多个其他错误。这是一个固定逻辑的版本:
@Override
public void handle(ActionEvent event) {
Thread thread = new Thread(() -> {
int temp = 0;
Calendar calendar = Calendar.getInstance();
System.out.println("Seconds in current minute = " + calendar.get(Calendar.SECOND));
temp = calendar.get(Calendar.SECOND);
int counter = 1;
do {
calendar = Calendar.getInstance() ;
if (temp != calendar.get(Calendar.SECOND)) {
System.out.println("Seconds in current minute = " + calendar.get(Calendar.SECOND));
double rotation = 6.0 * counter ;
Platform.runLater(() -> imageHolder2.rotateProperty().set(rotation) );
counter++;
temp = calendar.get(Calendar.SECOND);
}
} while (counter <= 60);
});
thread.setDaemon(true);
thread.start();
}
最后,请注意您也可以这样做:
@Override
public void handle(ActionEvent event) {
RotateTransition animation = new RotateTransition(Duration.seconds(60), imageHolder2);
animation.setByAngle(360);
animation.play();
}
我正在尝试构建一个模拟秒表。有一个按钮,当我单击时,秒表开始以秒为单位计数。
请注意,此代码运行良好(技术上),但就我基于 "java language" 的逻辑 or/and 我基于思维的逻辑而言存在一些问题。我也知道我的秒表会在几毫秒内出现一些边际误差。有两个打印语句可以检查我的逻辑。请注意,我有一些 C 编码经验,但对此并不陌生。 编辑:平台是javaFX
现在,我在使用这段代码时遇到了 3 个问题。
技术写的三个问题:
1- 第二个打印语句的输出与第一个相同。即,我的 IF 语句不起作用,因为 temp + 1 仍然等于当前秒数,尽管如果我们考虑到它们之间的代码行执行得更快这一事实,这是不可能的。 更新:此 (1) 已解决。
2- 忽略问题 (1),我的图像没有旋转,尽管自执行 IF 语句以来它应该旋转。请注意,我正在使用 stackpane 并将该图像添加到我的布局中,但它只是停留在 0 度并且没有做任何事情。
3- 即使我等待了太多时间,While 循环本身也不工作。我不确定在事件处理方法中是否使用 "okay" 或不使用 while 循环。
三题结构写法:
1- N/A
2- 我是否可以使用循环而不是使用按钮或其他方式从 even 方法内部在事件方法中连续更新我的布局元素?
3- 同 (2)
btn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
int temp = 0;
Calendar calendar = Calendar.getInstance();
System.out.println("Seconds in current minute = " + calendar.get(Calendar.SECOND));
temp = calendar.get(Calendar.SECOND);
int temp2 = temp + 60;
int counter = 1;
do {
System.out.println("Seconds in current minute = " + calendar.get(Calendar.SECOND));
if ((temp + 1) == calendar.get(Calendar.SECOND)) {
System.out.println("Seconds in current minute = " + calendar.get(Calendar.SECOND));
imageHolder2.rotateProperty().set(6.0 * counter);
counter++;
temp = calendar.get(Calendar.SECOND);
}
} while (temp2 != (calendar.get(Calendar.SECOND) + 60));
}
});
1) 我想你只是看到了第一个 System.out.println(...)
(从循环之前)和循环中的第一个,它们将产生相同的输出(除了非常罕见的(几次出现)每百万次运行?)在执行中间三行代码期间的秒数 "tick over" 的情况)。
2) 这才是真正的问题。您的循环在 FX 应用程序线程中是 运行(忙碌)(因为它是由事件处理程序调用的)。这是用于更新 UI 和处理事件的同一个线程。因为你让这个线程一直忙,所以在你的循环完成之前它没有任何机会更新 UI 。您需要在后台线程中执行此循环,并在 FX 应用程序线程上安排 UI 更新,或者(更容易)使用动画 API 来执行此操作。
3) 你的逻辑有很多错误。 (1) 在开始循环之前分配 calendar
,并且从不更新它;所以它总是代表处理程序启动的瞬间。 (2) 你把temp2
赋值为seconds + 60
然后你的循环条件是temp2 != seconds + 60
,这显然是假的,所以循环退出。即使您在循环迭代中更新 calendar
,seconds
字段在循环的第一次迭代中发生变化的可能性极小,因此您几乎肯定会立即退出循环。 (3) 如果更新calendar
,seconds
字段将始终为0到59(含)之间的值,即它将"wrap"为60。temp2
将始终为至少 60,所以一旦你修复了错误 (1) 和 (2),你的循环将永远不会退出... (4) if (temp + 1 == calendar.get(Calendar.SECONDS))
将在分钟结束时失败,因为 60 != 0
,所以你的一旦发生这种情况,迭代就会停止。
您可以使用 Timeline
来做到这一点:
@Override
public void handle(ActionEvent event) {
Timeline timeline = new Timeline(
// key frame that updates rotation on each second:
new KeyFrame(Duration.seconds(1), e -> {
imageHolder2.setRotate(imageHolder2.getRotate() + 6);
System.out.println("Seconds in current minute = " + Calendar.getInstance().get(Calendar.SECOND));
})
);
// repeat 60 times:
timeline.setCycleCount(60);
timeline.play();
}
如果您想使用您的原始代码,您需要将其包装在后台线程中,并在 FX 应用程序线程上安排 UI 更新。如上所述,您的代码中还有多个其他错误。这是一个固定逻辑的版本:
@Override
public void handle(ActionEvent event) {
Thread thread = new Thread(() -> {
int temp = 0;
Calendar calendar = Calendar.getInstance();
System.out.println("Seconds in current minute = " + calendar.get(Calendar.SECOND));
temp = calendar.get(Calendar.SECOND);
int counter = 1;
do {
calendar = Calendar.getInstance() ;
if (temp != calendar.get(Calendar.SECOND)) {
System.out.println("Seconds in current minute = " + calendar.get(Calendar.SECOND));
double rotation = 6.0 * counter ;
Platform.runLater(() -> imageHolder2.rotateProperty().set(rotation) );
counter++;
temp = calendar.get(Calendar.SECOND);
}
} while (counter <= 60);
});
thread.setDaemon(true);
thread.start();
}
最后,请注意您也可以这样做:
@Override
public void handle(ActionEvent event) {
RotateTransition animation = new RotateTransition(Duration.seconds(60), imageHolder2);
animation.setByAngle(360);
animation.play();
}