使用循环从事件方法内部在事件方法中连续更新我的布局元素

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,这显然是假的,所以循环退出。即使您在循环迭代中更新 calendarseconds 字段在循环的第一次迭代中发生变化的可能性极小,因此您几乎肯定会立即退出循环。 (3) 如果更新calendarseconds字段将始终为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();
}