gpt4 book ai didi

JavaFX - 调用 UI 更新方法并在中间暂停

转载 作者:行者123 更新时间:2023-12-02 11:37:11 24 4
gpt4 key购买 nike

我目前正在开发一个JavaFx学校项目,我尝试在GridPane上移动imageView。移动应该在 UI 上按顺序可视化/更新

我尝试了AnimationTimersThreads以及一切,但我在这个领域没有那么丰富的经验。我在我的 PlaygroundController 中启动一个线程,并在每次方法结束时调用 sleep 。

在第二个代码片段中,我创建了一个 PlaygroundController 类的对象,并连续调用这些方法三次。我的目标是使用 moveRight() 方法将 ImageView 1 列向右移动,暂停一秒钟,然后向下移动,调用 moveDown ()方法等等。

使用我的代码,它会在 3 秒延迟后同时执行所有 3 个方法。

private Thread thread;
public PlaygroundController() {
thread = new Thread();
thread.start();

}

public void run(ActionEvent evt) throws InterruptedException {
Level1Solution level = new Level1Solution(this);

}

public void moveRight() throws InterruptedException {
if(GridPane.getColumnIndex(avatarIcon) < 10) {
GridPane.setColumnIndex(avatarIcon, GridPane.getColumnIndex(avatarIcon) +1);

}else{
Alert alert = new Alert(AlertType.WARNING);
alert.setTitle("Fehler!");
alert.setHeaderText("Weiter geht es nicht!");
alert.setOnHidden(evt -> Platform.exit());
alert.show();
}
avatarColumn = GridPane.getColumnIndex(avatarIcon);
Thread.sleep(1000);
}

第二个片段:

package controller;

public class Level1Solution {


PlaygroundController solution;

public Level1Solution(PlaygroundController solution) throws InterruptedException {

this.solution = solution;
solution.moveRight();
solution.moveDown();
solution.moveRight();

}

}

最佳答案

您的 Level1Solution 构造函数可能是在 FX 应用程序线程上执行的。它在 PlaygroundController 实例上调用三个方法,每个方法(大概)都会更改 UI 元素的位置,然后将当前(即 FX 应用程序)线程暂停一秒钟。

请注意,您在 PlaygroundController 中创建的线程实际上并没有执行任何操作:它没有 Runnable 并且不会覆盖其自己的 run() 方法,所以它基本上什么也不做。您启动该线程 - 因此它在后台执行其 run() 方法,并且它将立即退出(因为它没有任何事情可做)。

FX 应用程序线程负责渲染 UI。由于您在 FX 应用程序线程上执行 Level1Solution 构造函数,因此在该构造函数完成之前无法呈现该 UI;即三秒后,用户界面将反射(reflect)您对其所做的所有更改。

出于这样的原因,您永远不应该阻止 FX 应用程序线程。另请注意,对 UI 的实际更改必须在该线程上进行。

要在特定时间点在 FX 应用程序线程上执行代码,您应该使用某种 animation 。对于您的用例,Timeline 效果很好;只需为每个时间点定义关键帧,并使用调用该方法的事件处理程序:

public class Level1Solution {


PlaygroundController solution;

public Level1Solution(PlaygroundController solution) throws InterruptedException {

this.solution = solution;

Timeline timeline = new Timeline(
new KeyFrame(Duration.seconds(0), e -> solution.moveRight()),
new KeyFrame(Duration.seconds(1), e -> solution.moveDown()),
new KeyFrame(Duration.seconds(2), e -> solution.moveRight()));

timeline.play();
}

}

当然,还要从 PlaygroundController 中删除 Thread 和暂停:

public PlaygroundController() { 
}

public void run(ActionEvent evt) throws InterruptedException {
Level1Solution level = new Level1Solution(this);

}

public void moveRight() throws InterruptedException {
if(GridPane.getColumnIndex(avatarIcon) < 10) {
GridPane.setColumnIndex(avatarIcon, GridPane.getColumnIndex(avatarIcon) +1);

}else{
Alert alert = new Alert(AlertType.WARNING);
alert.setTitle("Fehler!");
alert.setHeaderText("Weiter geht es nicht!");
alert.setOnHidden(evt -> Platform.exit());
alert.show();
}
avatarColumn = GridPane.getColumnIndex(avatarIcon);

// never block the UI thread:
// Thread.sleep(1000);
}
<小时/>

如果您有特定要求,即 Level1Controller 构造函数必须调用这三个方法,并且不以任何方式处理暂停本身,那么它会变得更多难的。一种方法是您调用的方法将任务提交给单线程执行器,它们提交的任务执行 UI 操作,然后暂停一段时间。单线程上的暂停将确保在执行任何其他任务之前有一段时间。请注意,在这种情况下,任务将在后台线程上进行,因此对 UI 的实际更改必须包含在对 Platform.runLater(...) 的调用中,以便在外汇应用程序线程。

这一切看起来都是这样的:

public class PlaygroundController {

private ExecutorService exec ;

public PlaygroundController() {
// single thread executor using a daemon thread
// (so it will not prevent application exit)
exec = Executors.newSingleThreadExecutor(runnable -> {
Thread t = new Thread(runnable);
t.setDaemon(true);
return t ;
});
}

public void run(ActionEvent evt) throws InterruptedException {
Level1Solution level = new Level1Solution(this);

}

public void moveRight() throws InterruptedException {

Runnable task = () -> {
Platform.runLater(() -> {
if(GridPane.getColumnIndex(avatarIcon) < 10) {
GridPane.setColumnIndex(avatarIcon, GridPane.getColumnIndex(avatarIcon) +1);

} else {
Alert alert = new Alert(AlertType.WARNING);
alert.setTitle("Fehler!");
alert.setHeaderText("Weiter geht es nicht!");
alert.setOnHidden(evt -> Platform.exit());
alert.show();
}
avatarColumn = GridPane.getColumnIndex(avatarIcon);
});
Thread.sleep(1000);
};

exec.submit(task);
}

// ...

}

然后就

public class Level1Solution {


PlaygroundController solution;

public Level1Solution(PlaygroundController solution) throws InterruptedException {

this.solution = solution;
solution.moveRight();
solution.moveDown();
solution.moveRight();

}

}

应该达到预期的结果。不过,这种方法似乎有点过于复杂:上面的动画解决方案更为可取。

关于JavaFX - 调用 UI 更新方法并在中间暂停,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48844015/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com