JavaFX,primaryStage.show()之后的代码,怎么样?

问题描述 投票:0回答:3

我的目标是在舞台+场景出现后每秒看到矩形的颜色变化。

我研究并尝试了几件事:

  • primaryStage.show() 下的代码 [查看我的示例代码]
  • primaryStage.setOnShown()或primaryStage.setOnShowing()
  • 来自舞台的事件处理程序
  • 场景中的事件处理程序
  • 带有事件处理程序的按钮

一切都是徒劳。 在大多数情况下,舞台出现,然后程序在背景中执行颜色变化(没有可视化),最后场景出现并显示最终结果。或者版本 2:我什么也没看到,代码通过了,最后立即得到了最终结果。

这是我的代码:

package sample;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;


public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        GridPane gridPane = new GridPane();

        Rectangle[] recs = new Rectangle[10];
        for (int i = 0; i < recs.length; i++) {
            recs[i] = new Rectangle(30, 30, Color.GREEN);
            recs[i].setStroke(Color.BLACK);
            gridPane.add(recs[i], i, 0);
        }

        primaryStage.setTitle("Code after primaryStage.show()");
        primaryStage.setScene(new Scene(gridPane, 400, 300));
        primaryStage.show();


        for (Rectangle rec : recs) {   
            Thread.sleep(1000);    
            rec.setFill(Color.ORANGE);
        }
    }


    public static void main(String[] args) {
        launch(args);
    }
}
java multithreading javafx sleep show
3个回答
2
投票

这里的问题是您的循环在主应用程序线程上运行,因此它会锁定任何 GUI 更新,直到完成为止。

在自己的线程上执行循环并使用

Platform.runLater()
更新每个矩形:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;


public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        GridPane gridPane = new GridPane();

        Rectangle[] recs = new Rectangle[10];
        for (int i = 0; i < recs.length; i++) {
            recs[i] = new Rectangle(30, 30, Color.GREEN);
            recs[i].setStroke(Color.BLACK);
            gridPane.add(recs[i], i, 0);
        }

        primaryStage.setTitle("Code after primaryStage.show()");
        primaryStage.setScene(new Scene(gridPane, 400, 300));
        primaryStage.show();

        new Thread(() -> {
            for (Rectangle rec :
                    recs) {
                try {
                    Thread.sleep(1000);
                    Platform.runLater(() -> rec.setFill(Color.ORANGE));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

    }

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

那么发生了什么?

new Thread(() -> {

在应用程序后台打开一个新线程,以便 UI 保持响应。

然后我们可以在

try/catch
块内开始循环。

Platform.runLater(() -> rec.setFill(Color.ORANGE));

使用后台线程时,重要的是要知道您无法直接更改 UI。此行告诉 JavaFX 在 JavaFX 应用程序线程上执行

rec.setFill()
语句。

.start();

您已经创建了新的

Thread
,这只是开始。


1
投票

这是使用

TimeLine
的另一种方法。代码来自这里

import java.util.concurrent.atomic.AtomicInteger;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Main extends Application
{

    @Override
    public void start(Stage primaryStage) throws Exception
    {
        GridPane gridPane = new GridPane();

        Rectangle[] recs = new Rectangle[10];
        for (int i = 0; i < recs.length; i++) {
            recs[i] = new Rectangle(30, 30, Color.GREEN);
            recs[i].setStroke(Color.BLACK);
            gridPane.add(recs[i], i, 0);
        }

        primaryStage.setTitle("Code after primaryStage.show()");
        primaryStage.setScene(new Scene(gridPane, 400, 300));
        primaryStage.show();

        AtomicInteger counter = new AtomicInteger();
        Timeline oneSecondsWonder = new Timeline(new KeyFrame(Duration.seconds(1), (ActionEvent event) -> {
            System.out.println("this is called every 1 second on UI thread");
            recs[counter.getAndIncrement()].setFill(Color.ORANGE);
        }));
        oneSecondsWonder.setCycleCount(recs.length);
        oneSecondsWonder.play();
    }

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

0
投票
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class Game extends Application {

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

  @Override
  public void start(Stage primaryStage) {
    Group root = new Group();
    Scene scene = new Scene(root, 800, 600);

    Rectangle train = new Rectangle(0, 300, 50, 50);
    train.setFill(Color.GREEN);

    Rectangle[] trees = new Rectangle[10];
    for (int i = 0; i < 10; i++) {
      trees[i] = new Rectangle((int) (Math.random() * 800), (int) (Math.random() * 600), 20, 20);
      trees[i].setFill(Color.GREEN);
    }

    Rectangle water = new Rectangle((int) (Math.random() * 800), (int) (Math.random() * 600), 10, 10);
    water.setFill(Color.BLUE);

    root.getChildren().addAll(train, trees, water);

    AnimationTimer timer = new AnimationTimer() {
      @Override
      public void handle(long now) {
        train.setX(train.getX() + 5);
        if (train.getX() > 800) {
          train.setX(0);
        }
      }
    };
    timer.start();

    primaryStage.setTitle("Game");
    primaryStage.setScene(scene);
    primaryStage.show();
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.