Javafx实时线程更新 [英] Javafx live thread updates

查看:109
本文介绍了Javafx实时线程更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在与Javafx和线程同时工作,我一直遇到这个问题,我做了一个按钮然后当点击按钮时(使用事件处理程序)我做了一个for循环,将按钮更改为1,2, 3,4,5然后在每个中间延迟一秒钟。倒数!

I'm working with Javafx and threads simultaneously and I constanly run into this problem where I make a button and then when the button is clicked (using event handlers) I make a for loop that changes the button to 1,2,3,4,5 and then delays for a second in the middle of each. Like a count down!

但会发生的是延迟5秒并将按钮文本更改为5.

But what happens is it delays for 5 seconds and changes the text of button to 5.

问题我希望看到它在1到5之间变化,但我看到的是在5秒延迟结束时的5。我会假设它改变了按钮文本,但我没有看到它。我可能需要处理 Javafx 类中的 .show()方法。

The problem is I want to see it change between 1 and 5 but all I see is 5 at the end of a 5 second delay. I would assume that it changing the button text but I don't see it. I might have to to do with the .show() method in the Javafx class.

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);
        }
    }
}


推荐答案

为什么您的代码不起作用

您的代码不起作用的原因是您阻止了FX应用程序主题。

The reason your code doesn't work is that you are blocking the FX Application Thread.

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

Like (almost?) all UI toolkits, JavaFX is a single-threaded UI toolkit. This means that all event handlers, and all the rendering of the UI, are performed on a single thread (called the FX Application Thread).

在您的代码中,您有一个事件处理程序,运行时间超过一秒,因为它通过调用 Thread.sleep(...)暂停一秒钟。当该事件处理程序正在运行时,无法重绘UI(因为单个线程不能同时执行两项操作)。因此,当按钮文本的值立即更改时,在句柄(...)方法完成运行之前,新值实际上不会在屏幕上呈现。如果在handle方法中有 for 循环,则在整个循环(以及方法中的任何其他内容)完成之前不会呈现任何内容。

In your code, you have an event handler that takes more than a second to run, because it pauses for a second via a call to Thread.sleep(...). While that event handler is running, the UI cannot be redrawn (because a single thread cannot do two things at once). So while the value of the button's text has changed immediately, the new value won't actually be rendered on the screen until the handle(...) method has finished running. If you had a for loop in the handle method, nothing would be rendered until the entire loop (and anything else in the method) had completed.

如何修复

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

The simplest way to do what you want in JavaFX is to use a Timeline to handle the pause. The Timeline manages the threading appropriately for you:

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 Animation API (另见教程)非常有用,尤其是时间轴 PauseTransition

In general, for changing the appearance of the user interface at specific time points, the JavaFX Animation API (see also the tutorial) can be useful, especially Timeline and PauseTransition.

执行此操作的低级方法是自己创建 Thread 并暂停该线程。这是更高级的:您需要小心更新FX应用程序线程上的UI,而不是您创建的线程。您可以通过调用调用Platform.runLater(...)来执行此操作:

A "lower-level" way to do this would be to create a Thread yourself and pause in that thread. This is much more advanced: you need to be careful to update the UI on the FX Application Thread, not on the thread you created. You can do this with a call to Platform.runLater(...):

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中线程的更多一般信息,请使用看看这篇文章:使用线程发出数据库请求

For more general information on threading in JavaFX, have a look at this post: Using threads to make database requests

这篇关于Javafx实时线程更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆