当前位置: 首页 > 知识库问答 >
问题:

Javafx实时线程更新

袁卓
2023-03-14

我同时使用Javafx和线程,我经常遇到这个问题,我制作了一个按钮,然后当单击按钮时(使用事件处理程序),我制作了一个for循环,将按钮更改为1、2、3、4、5,然后在每个按钮中间延迟一秒钟。就像倒计时一样!

但实际情况是,它会延迟5秒钟,并将按钮的文本更改为5。

问题是我想看到它在1到5之间变化,但我看到的只是5秒延迟结束时的5。我假设它会更改按钮文本,但我看不到它。我可能不得不处理<代码>。在Javafx类中显示()方法。

public class HewoWorld extends Application implements EventHandler<ActionEvent>
{
    Thread t = new Thread();
    Button butt;
    boolean buttWasClicked = false;
    Circle circ1 = new Circle(40, 40, 30, Color.RED);
    Circle circ2 = new Circle(100, 100, 30, Color.BLUE);
    Group root;
    Scene scene;
    Stage disStage = new Stage();
    int i = 1;
    public static void main(String[] args)
    {
        launch(args);
    }
    public void start(Stage stage) throws Exception 
    {

        disStage.setTitle("tests stuffs");
        Screen screen = Screen.getPrimary();
        Rectangle2D bounds = screen.getVisualBounds();
        double windh = bounds.getHeight()/2+150;//sets height of screen 
        double windw = bounds.getWidth()/3;//sets width of screen 
        Pane layout = new Pane();
        butt = new Button();
        butt.setText("Hello world");


        root = new Group(circ1, circ2, butt);
        scene = new Scene(root, 800, 400);
        disStage.setWidth(windw);
        disStage.setHeight(windh);


        butt.setLayoutX(200);
        butt.setLayoutY(200);
        butt.setOnAction(this);
        disStage.setScene(scene);
        disStage.show();
    }
     public void handle(ActionEvent event) 
    {
        if (event.getSource() == butt && buttWasClicked == false) 
        {
            try
            {
                butt.setText(i+"");
                t.sleep(1000);
                i++;
            }
            catch(Exception q)
            {

            } 
            circ1 = new Circle(40, 40, 30, Color.BLACK);
            circ2 = new Circle(100, 100, 30, Color.RED);
        }
    }
}

共有3个答案

花阳秋
2023-03-14

在这种情况下,您需要一个计时器来每秒运行一次,并在每次命中时增加一个计数器。据我所知,在javafx中创建计时器的最佳方法是使用时间线。https://stackoverflow.com/a/9966213/4683264.

int i = 0;// class field
// ....
Timeline fiveSecondsWonder = new Timeline(new KeyFrame(Duration.seconds(1), event -> 
                                             button.setText(++i)));
fiveSecondsWonder.setCycleCount(5);// repeat five times
fiveSecondsWonder.play();
常彭薄
2023-03-14

您需要做的是用以下方法替换使用的线程:

scheduler = Executors.newScheduledThreadPool(1);

scheduler.scheduleAtFixedRate(

        new Runnable(){


            @Override
            public void run() {
               Platform.runLater(new Runnable() {

                   @Override
                   public void run() {

                           //Here your code to change the number by for example incrementig the value of the button
                   }
               });

            }
        }, 
        1000, 
        80, 
        TimeUnit.MILLISECONDS);  

1如果有帮助: D

濮阳唯
2023-03-14

为什么代码不起作用

代码无法工作的原因是您正在阻止FX应用程序线程。

就像(几乎?)所有UI工具包,JavaFX是一个单线程UI工具包。这意味着所有事件处理程序和UI的所有呈现都在单个线程(称为FX应用程序线程)上执行。

在代码中,您有一个运行时间超过1秒的事件处理程序,因为它通过调用线程暂停1秒。睡眠(…) 。当该事件处理程序运行时,无法重新绘制UI(因为单个线程不能同时执行两件事)。因此,虽然按钮文本的值立即发生了更改,但直到<代码>句柄(…)出现,新值才真正呈现在屏幕上 方法已完成运行。如果handle方法中有一个for循环,那么在整个循环(以及方法中的任何其他内容)完成之前,都不会渲染任何内容。

如何修复它

在JavaFX中执行所需操作的最简单方法是使用时间线来处理暂停。时间线为您适当地管理线程:

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Duration;

public class CountingButton extends Application {


    @Override
    public void start(Stage primaryStage) {

        Button button = new Button("Count");

        Timeline timeline = new Timeline();
        for (int count = 0; count <= 5 ; count++) {
            final String text = Integer.toString(count);
            KeyFrame frame = new KeyFrame(Duration.seconds(count), event -> 
                button.setText(text));
            timeline.getKeyFrames().add(frame);
        }

        button.setOnAction(e -> timeline.play());

        primaryStage.setScene(new Scene(new StackPane(button), 120, 75));
        primaryStage.show();
    }


    public static void main(String[] args) {
        launch(args);
    }
}

一般来说,对于在特定时间点更改用户界面的外观,JavaFX动画API(另请参见教程)非常有用,尤其是时间线和暂停转换。

一种“较低级别”的方法是自己创建一个线程并在该线程中暂停。这要高级得多:您需要小心更新FX应用程序线程上的UI,而不是您创建的线程上的UI。您可以通过调用Platform.run稍后(...)来做到这一点:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class CountingButton extends Application {


    @Override
    public void start(Stage primaryStage) {

        Button button = new Button("Start");

        button.setOnAction(e -> {
            Thread thread = new Thread(() -> {
                for (int i = 0; i <= 5 ; i++) {
                    final String text = "Count: "+i ;
                    Platform.runLater(() -> button.setText(text));
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException exc) {
                        exc.printStackTrace();
                    }
                }
            });
            thread.start();
        });

        primaryStage.setScene(new Scene(new StackPane(button), 120, 75));
        primaryStage.show();
    }


    public static void main(String[] args) {
        launch(args);
    }
}

有关JavaFX中线程的更多一般信息,请查看这篇文章:使用线程发出数据库请求

 类似资料:
  • 问题内容: 我同时使用Javafx和线程,并且遇到了这个问题,我制作了一个按钮,然后单击该按钮(使用事件处理程序)时,我做了一个for循环,将按钮更改为1,2,3,4 ,5,然后在每个中间延迟一秒钟。像倒计时! 但是发生的事情是延迟了5秒钟,并将按钮的文本更改为5。 问题是我希望看到它在1到5之间变化,但我看到的只是在5秒延迟结束时为5。我认为它会更改按钮文本,但看不到。我可能与类中的方法有关。

  • 在我的JavaFX应用程序中,我想显示来自后台线程的实时数据。有人知道如何从后台线程更新linechart吗?谢谢你。下面是一些示例代码。 TM的 预览图像 采样控制器 } 处理类。启动线程。 任务类。执行任务的线程类 主类 样品fxml

  • 我有课: 阅读了手册后,我明白了我们需要在FX线程中刷新UI。我已经使用了platform.runlater(),但是在流结束时UI变慢了。 为我糟糕的英语感到抱歉。

  • 问题内容: 我有一个javafx应用程序和一个工作线程,通过来实现,它执行一个漫长的过程,即压缩并上传一组文件。 我已通过将任务进度连接到进度条。 除此之外,我想将有关正在处理的项目的详细状态报告到ui中。 也就是说,正在处理的文件的名称及其大小以及单个文件处理可能引起的任何错误。 用这些信息更新UI不能从工作线程中完成,最多我可以将其添加到同步集合中。 但是然后我需要一些事件来通知UI新数据可用

  • 我有一个javafx应用程序和一个通过实现的工作线程,它执行一个很长的过程,即压缩和上载一组文件。 我已通过将任务进度连接到进度条。 除此之外,我还希望将正在处理的项的详细状态报告到UI中。即正在处理的文件的名称及其大小和单个文件进程可能产生的任何错误。 不能从辅助线程中使用这些信息更新UI,最多只能将其添加到同步集合中。 但我需要一些事件来通知UI新数据可用。 javafx是否对此问题有特定的支

  • 所以我在这个问题上有点卡住了。我有一个非常基本的游戏,你用箭头键在网格周围移动一艘船。 我添加了另一个线程与一些怪物,应该自动漫游网格。我可以从打印语句中看到线程正在运行怪物正在移动,但是,图像位置没有更新。 我发现了一些类似的问题,有很多建议可以使用。但我不确定它是否符合我的具体情况,如果符合,如何实施。 下面是怪物类正在做的事情,每秒将怪物向右移动一个空间。就像我提到的,每次调用时,我都会记录