我发布了一个类似于此的问题,但我不够具体。下面是我的代码的简化版本:
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.scene.control.ProgressBar;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.layout.HBox;
import javafx.scene.Scene;
import javafx.concurrent.Task;
import javafx.stage.Stage;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.scene.control.Button;
import javafx.scene.control.MenuBar;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.Separator;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.text.Text;
import javafx.scene.text.Font;
import javafx.geometry.Pos;
import java.net.URL;
import javafx.scene.image.Image;
import javafx.scene.layout.GridPane;
import javafx.scene.control.Slider;
public class ProgressTest extends Application {
boolean play = true;
int x = 0;
@Override
public void start(Stage stage) {
GridPane pane = new GridPane(); //pane and Hboxes
HBox hbox = new HBox();
Button update = new Button("Start");
update.setOnAction( e -> {
while(play == true)
{
System.out.println(++x);
}
});
Button pause = new Button("Pause");
pause.setOnAction( e -> {
if(play == true)
{
pause.setText("Play");
play = false;
}
else
{
pause.setText("Pause");
play = true;
}
});
hbox.getChildren().addAll(update, pause);
pane.add(hbox, 0, 1);
Scene scene = new Scene(pane);
stage.setMaxWidth(655);
stage.setMaxHeight(620);
stage.setTitle("Gallery!");
stage.setScene(scene);
stage.sizeToScene();
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}这段代码的思想是,当用户单击“开始”按钮时,程序应该打印出向上的x,并在用户点击“暂停”时暂停,当用户点击"Play“时再继续。
问题是,每当我单击"Play“按钮时,程序就会进入一个无限循环,并且我无法按下暂停按钮来停止它。我这样做有什么不对吗?有什么窍门能让这件事成功吗?任何帮助都将不胜感激。
此外,我知道其中一些可能存在语法错误,但我知道代码副本是正确的,我更多地考虑了如何使其工作的逻辑。
发布于 2017-11-05 23:20:42
您的实现有两个大问题:
play设置为false之后,循环将退出,单击简历将什么也做不了。有几种方法可以解决这个问题。我将使用Thread和CountDownLatch演示一个。
我无法解释问题范围内的线程是什么(到处都有大量的材料),但这里的相关问题是,在一个不是JavaFX线程的线程上执行代价高昂的操作将解决第一点。
CountDownLatch用于阻止线程(或多个)的执行,直到锁存/断开为止,线程将继续执行锁存。它是用一个int初始化的,它表示在发布之前需要计数的次数。到达闩锁的await方法的线程会阻塞,直到闩锁的countDown方法被调用指定的次数为止。
下面是一个示例代码:
import java.util.concurrent.CountDownLatch;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class ProgressTest extends Application {
volatile CountDownLatch cl = new CountDownLatch(1);
@Override
public void start(Stage stage) {
Thread thread = new Thread(() -> {
int x = 0;
while (true) {
try {
cl.await();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println(++x);
}
});
thread.setDaemon(true);
Button update = new Button("Start");
update.setOnAction(e -> {
if (!thread.isAlive()) {
cl.countDown();
thread.start();
}
});
BooleanProperty running = new SimpleBooleanProperty(true);
Button pause = new Button("Pause");
pause.textProperty().bind(Bindings.when(running).then("Pause").otherwise("Play"));
pause.setOnAction(e -> {
if (running.get()) {
cl = new CountDownLatch(1);
}
else {
cl.countDown();
}
running.set(!running.get());
});
HBox hbox = new HBox(update, pause);
Scene scene = new Scene(hbox);
stage.setScene(scene);
stage.setTitle("Gallery!");
stage.sizeToScene();
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}线程与while(true)循环一起“尽可能快地”释放数字,只有通过到达await方法才能暂停它。当您按Start时,闩锁断了,线程继续启动和执行。当您按下“暂停”时,就会在它的位置创建一个新的锁存器(闩锁是一个一次性的东西,不能重置),这会导致线程在await中等待,直到有人用countDown方法破坏它(一次调用就足够了,因为我们用1实例化了它)。这就是按压简历所做的。
在线程上调用setDaemon(true)确保它允许JVM退出而无需等待它。如果线程必须在JVM存在之前完成(例如,它不是后台线程),则可以删除它。
Iv'e制作了锁存器volatile,它保证不同的线程会看到相同的值。还请参阅您是否在Java中使用过易失性关键字?和其他可用资源。在这种特殊情况下,您不需要点点线程同步,因此它不会产生明显的效果,但它仍然应该存在。
请注意,我在Start上添加了一个小的检查,即线程尚未运行,因为在线程运行时启动线程会引发异常。如果在执行过程中按下Start,您没有指定该做什么。
虽然与您的问题无关,但Iv'e演示了如何利用JavaFX结合 API使按钮的文本更新自动具有boolean的值。我将控件boolean“提升”到属性,并将按钮的文本绑定到其值。不过,在这种情况下,它可能不太有用。
备注:
sizeToScene,这使得前面的调用变得多余。==检查布尔值,您可以直接使用它:if (b == true)等效于if (b),if (b == false)等效于if (!b)。boolean更好的名称是表示状态(“运行”/“暂停”),而不是动作(“运行”/“暂停”)。https://stackoverflow.com/questions/47125540
复制相似问题