Java FX如何'Stop'线程中途并重新启动或销毁它
Java FX How to 'Stop' Thread Midway and Restart it or destroy it
无法停止线程中途和重新启动添加节点线程。
这就是我得到的
这就是我需要的每当我按下刷新按钮[=时,我都想要这样的东西74=]
clean screen and Restart(例如。A 到 N 按正确顺序排列)
为什么?所以我可以在刷新前选择不同的列表。
背景故事 (忽略)
一个月以来,我一直在做一个关于 JavaFX 的小项目,但这个问题一直困扰着我。我做了我的研究并试图弄清楚但没有。如果有人在正确的道路上引导我,我真的很感激。请高亮这个问题,这样其他人就不用浪费那么多时间了
我有 JavaFX 控制器
@FXML public FlowPane flow_panel;
MyPlatform mp = new MyPlatform(); // A class that implements Runnable
Thread t;
boolean first_time_click = true; // To check Whether i clicked '1st' time or 'second' time
@FXML
private void Refresh_Btn(ActionEvent event)
{
System.out.println("Refresh btn");
t = new Thread(mp); //Creating Thread object
if(first_time_click == true) { first_time_click = false;
MyPlatform.stop = false; //Thread object.Stop, When false do nothing
flow_panel.getChildren().clear(); // cleaning screen
System.out.println("Start Thread");
t.setDaemon(true);
t.start(); //Start Thread
} else if(first_time_click == false){ first_time_click = true;
MyPlatform.stop = true; //Exist loop
t.interrupt(); // I thought 't.interrupt()' it work but nothing
System.out.println("Stop Thread");
flow_panel.getChildren().clear(); // cleaning screen
MyPlatform.stop = false; //Thread object.Stop, When false do nothing
t.setDaemon(true);
t.start(); //Start Thread
System.out.println("Stoped Thread Started again");
}
}
然后我有一个名为 MyPlatform 的 class 实现了 Runnable
import javafx.application.Platform;
import javafx.scene.control.Button;
import setups.WindowSetupConfig;
public class MyPlatform implements Runnable
{
public static boolean stop = false;
@Override
public void run()
{
for (String name : ListOfNames.getlist())
{
if(stop) // Exit for loop if true
{
break;
}
Platform.runLater(new Runnable()
{
@Override
public void run()
{
Button btn = new Button("Button : "+name);
System.out.println(name);
//Adding that button to FlowPane
WindowSetupConfig.getController().flow_panel.getChildren().add(btn);
}
});
try {
Thread.sleep(1000); // Wait for 1 sec, Controlling speed
} catch (InterruptedException e) { // try catch it needed for some reason
e.printStackTrace();
}
}
}
}
我有一个字符串列表。最初该列表将包含 500 多个名称
import java.util.ArrayList;
public class ListOfNames
{
private static ArrayList<String> list_of_names ;
public ListOfNames()
{
list_of_names = new ArrayList<>();
list_of_names.add("A");
list_of_names.add("B");
list_of_names.add("C");
list_of_names.add("D");
list_of_names.add("E");
list_of_names.add("F");
list_of_names.add("G");
list_of_names.add("H");
list_of_names.add("I");
list_of_names.add("J");
list_of_names.add("K");
list_of_names.add("L");
list_of_names.add("M");
list_of_names.add("N");
}
public static ArrayList<String> getlist() {
return list_of_names;
}
}
每当我 按下 刷新按钮 我想停止线程 中途 添加点头流量面板。
使用 flow_panel.getChildren().clear(); 清理 FlowPane
并从列表的开头重新开始
基本上
-停止
-清洁
-重启
如果有任何方法可以使用 Service 或 task 来完成,那就太好了
我找到了解决问题的方法。现在我的问题是有没有更好的方法来达到相同的结果
因为我正在和黄色交战,这意味着我做错了
Luncher.java
package project;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Luncher extends Application
{
@Override
public void start(Stage primaryStage) {
try {
Parent root = FXMLLoader.load(getClass().getResource("Window.fxml"));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
System.err.println("Luncher Failed !" +e);
}
}
public static void main(String[] args)
{
launch(args);
}
}
Controller.java
package project;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.layout.FlowPane;
public class Controller implements Initializable
{
@FXML
public FlowPane flowPane;
//A class that implements Runable, So i can start a thead there
private MyRunableClass my_run_class;
private Thread t; //Thread object
@Override
public void initialize(URL location, ResourceBundle resources)
{
new ListOfNames(); //Init list of names and creating Array list, In real program i will get this list from database
my_run_class = new MyRunableClass(this);
}
@FXML
void clear_Button(ActionEvent event)
{
flowPane.getChildren().clear();
}
@FXML
void start_Button(ActionEvent event)
{
t = new Thread(my_run_class);
t.start();
}
@FXML
void stop_Button(ActionEvent event) {
t.suspend(); ///NOT WORKING???????? any way to stop running thread
}
private boolean firstTime_thread_running = true; // To check Whether i clicked '1st' time or 'second' time
@FXML
void refresh_Button(ActionEvent event)
{
if(firstTime_thread_running == false){
//Stop
// my_run_class.stop = true; //Exist loop
t.suspend();
System.out.println("Suspend");
} else
{
firstTime_thread_running = false;
}
//Clean
flowPane.getChildren().clear(); // cleaning screen
System.out.println("Screen clear");
//Restart , well.. at least that what i want
t = new Thread(my_run_class);
t.setDaemon(true);
t.start(); //Start Thread
System.out.println("Stoped Thread Started again");
}
}
MyRunableClass.java
package project;
import javafx.application.Platform;
import javafx.scene.control.Button;
public class MyRunableClass implements Runnable
{
private Controller controller;
public MyRunableClass(Controller controller)
{
//Getting FXML Controller
this.controller = controller;
}
// public boolean stop = false;
@Override
public void run()
{
for (String name : ListOfNames.getlist())
{
// if(stop) // Exit for loop if true
// {
// break;
// }
Platform.runLater(new Runnable()
{
@Override
public void run()
{
Button btn = new Button("Button : "+name);
System.out.println(name);
controller.flowPane.getChildren().add(btn);
}
});
try {
Thread.sleep(1); // Wait for half sec this time
} catch (InterruptedException e) { // try catch it needed for some reason
e.printStackTrace();
}
}
}
}
ListOfNames.java
package project;
import java.util.ArrayList;
public class ListOfNames
{
private static ArrayList<String> list_of_names ;
public ListOfNames()
{
list_of_names = new ArrayList<>();
list_of_names.add("A");
list_of_names.add("B");
list_of_names.add("C");
list_of_names.add("D");
list_of_names.add("E");
list_of_names.add("F");
list_of_names.add("G");
list_of_names.add("H");
list_of_names.add("I");
list_of_names.add("J");
list_of_names.add("K");
list_of_names.add("L");
list_of_names.add("M");
list_of_names.add("N");
list_of_names.add("O");
list_of_names.add("P");
list_of_names.add("Q");
list_of_names.add("R");
list_of_names.add("S");
list_of_names.add("T");
list_of_names.add("U");
list_of_names.add("V");
list_of_names.add("W");
list_of_names.add("X");
list_of_names.add("Y");
list_of_names.add("Z");
}
public static ArrayList<String> getlist() {
return list_of_names;
}
}
Window.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.FlowPane?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="413.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="project.Controller">
<children>
<FlowPane fx:id="flowPane" layoutX="2.0" layoutY="61.0" prefHeight="352.0" prefWidth="600.0" style="-fx-border-color: #000000; -fx-border-insets: 1.1; -fx-border-width: 5;" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="61.0" />
<Button layoutX="405.0" layoutY="14.0" mnemonicParsing="false" onAction="#stop_Button" prefHeight="39.0" prefWidth="80.0" text="Stop" />
<Button layoutX="313.0" layoutY="14.0" mnemonicParsing="false" onAction="#start_Button" prefHeight="39.0" prefWidth="80.0" text="Star" />
<Button layoutX="497.0" layoutY="14.0" mnemonicParsing="false" onAction="#clear_Button" prefHeight="39.0" prefWidth="80.0" text="Clean" />
<Button layoutX="40.0" layoutY="14.0" mnemonicParsing="false" onAction="#refresh_Button" prefHeight="39.0" prefWidth="109.0" text="Refresh" />
</children>
</AnchorPane>
我没有阅读您的所有代码,但我将对如何取消和 "restart" 和 Task
进行一般性说明。
首先,不要使用Thread
的suspend
、stop
、resume
方法;他们被弃用是有原因的。
与所有后台任务一样,取消需要该后台任务的开发人员的合作。该任务必须在适当的时候检查它是否已被取消并做出相应的反应。一般是通过查询当前Thread
的中断状态来实现的,但是Task
class继承了FutureTask
更容易使用的isCancelled
方法。
模拟长运行工作的例子:
public class MyTask extends Task<Void> {
@Override
protected Void call() throws Exception {
for (int i = 0; i < 10_000; i++) {
if (isCancelled()) {
break;
}
updateMessage(Integer.toString(i));
Thread.sleep(1L);
updateProgress(i, 10_000);
}
return null;
}
}
您使用 Worker
接口的 cancel
方法取消了 Task
。注意在循环的每次迭代中检查 isCancelled
;当调用 cancel
方法时,Task
将尽早停止。此外,调用 Worker.cancel()
(或 Future.cancel(true)
)将中断 Thread
,这意味着任何可中断的操作(例如 Thread.sleep
)将抛出 InterruptedException
。
您可以通过观察 Task
的属性或添加事件处理程序来对 Task
成功、失败或取消做出反应。
MyTask task = new MyTask();
task.setOnSucceeded(event -> handleSucceededTask());
task.setOnFailed(event -> handleFailedTask());
task.setOnCancelled(event -> handleCancelledTask());
您可以在这些回调中进行清理并根据需要执行 new Task
。请注意,您必须启动一个新的 Task
,因为 Task
是一次性的。
无法停止线程中途和重新启动添加节点线程。
这就是我得到的
这就是我需要的每当我按下刷新按钮[=时,我都想要这样的东西74=]
clean screen and Restart(例如。A 到 N 按正确顺序排列)
为什么?所以我可以在刷新前选择不同的列表。
背景故事 (忽略) 一个月以来,我一直在做一个关于 JavaFX 的小项目,但这个问题一直困扰着我。我做了我的研究并试图弄清楚但没有。如果有人在正确的道路上引导我,我真的很感激。请高亮这个问题,这样其他人就不用浪费那么多时间了
我有 JavaFX 控制器
@FXML public FlowPane flow_panel;
MyPlatform mp = new MyPlatform(); // A class that implements Runnable
Thread t;
boolean first_time_click = true; // To check Whether i clicked '1st' time or 'second' time
@FXML
private void Refresh_Btn(ActionEvent event)
{
System.out.println("Refresh btn");
t = new Thread(mp); //Creating Thread object
if(first_time_click == true) { first_time_click = false;
MyPlatform.stop = false; //Thread object.Stop, When false do nothing
flow_panel.getChildren().clear(); // cleaning screen
System.out.println("Start Thread");
t.setDaemon(true);
t.start(); //Start Thread
} else if(first_time_click == false){ first_time_click = true;
MyPlatform.stop = true; //Exist loop
t.interrupt(); // I thought 't.interrupt()' it work but nothing
System.out.println("Stop Thread");
flow_panel.getChildren().clear(); // cleaning screen
MyPlatform.stop = false; //Thread object.Stop, When false do nothing
t.setDaemon(true);
t.start(); //Start Thread
System.out.println("Stoped Thread Started again");
}
}
然后我有一个名为 MyPlatform 的 class 实现了 Runnable
import javafx.application.Platform;
import javafx.scene.control.Button;
import setups.WindowSetupConfig;
public class MyPlatform implements Runnable
{
public static boolean stop = false;
@Override
public void run()
{
for (String name : ListOfNames.getlist())
{
if(stop) // Exit for loop if true
{
break;
}
Platform.runLater(new Runnable()
{
@Override
public void run()
{
Button btn = new Button("Button : "+name);
System.out.println(name);
//Adding that button to FlowPane
WindowSetupConfig.getController().flow_panel.getChildren().add(btn);
}
});
try {
Thread.sleep(1000); // Wait for 1 sec, Controlling speed
} catch (InterruptedException e) { // try catch it needed for some reason
e.printStackTrace();
}
}
}
}
我有一个字符串列表。最初该列表将包含 500 多个名称
import java.util.ArrayList;
public class ListOfNames
{
private static ArrayList<String> list_of_names ;
public ListOfNames()
{
list_of_names = new ArrayList<>();
list_of_names.add("A");
list_of_names.add("B");
list_of_names.add("C");
list_of_names.add("D");
list_of_names.add("E");
list_of_names.add("F");
list_of_names.add("G");
list_of_names.add("H");
list_of_names.add("I");
list_of_names.add("J");
list_of_names.add("K");
list_of_names.add("L");
list_of_names.add("M");
list_of_names.add("N");
}
public static ArrayList<String> getlist() {
return list_of_names;
}
}
每当我 按下 刷新按钮 我想停止线程 中途 添加点头流量面板。
使用 flow_panel.getChildren().clear(); 清理 FlowPane 并从列表的开头重新开始
基本上 -停止 -清洁 -重启
如果有任何方法可以使用 Service 或 task 来完成,那就太好了
我找到了解决问题的方法。现在我的问题是有没有更好的方法来达到相同的结果 因为我正在和黄色交战,这意味着我做错了
Luncher.java
package project;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Luncher extends Application
{
@Override
public void start(Stage primaryStage) {
try {
Parent root = FXMLLoader.load(getClass().getResource("Window.fxml"));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
System.err.println("Luncher Failed !" +e);
}
}
public static void main(String[] args)
{
launch(args);
}
}
Controller.java
package project;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.layout.FlowPane;
public class Controller implements Initializable
{
@FXML
public FlowPane flowPane;
//A class that implements Runable, So i can start a thead there
private MyRunableClass my_run_class;
private Thread t; //Thread object
@Override
public void initialize(URL location, ResourceBundle resources)
{
new ListOfNames(); //Init list of names and creating Array list, In real program i will get this list from database
my_run_class = new MyRunableClass(this);
}
@FXML
void clear_Button(ActionEvent event)
{
flowPane.getChildren().clear();
}
@FXML
void start_Button(ActionEvent event)
{
t = new Thread(my_run_class);
t.start();
}
@FXML
void stop_Button(ActionEvent event) {
t.suspend(); ///NOT WORKING???????? any way to stop running thread
}
private boolean firstTime_thread_running = true; // To check Whether i clicked '1st' time or 'second' time
@FXML
void refresh_Button(ActionEvent event)
{
if(firstTime_thread_running == false){
//Stop
// my_run_class.stop = true; //Exist loop
t.suspend();
System.out.println("Suspend");
} else
{
firstTime_thread_running = false;
}
//Clean
flowPane.getChildren().clear(); // cleaning screen
System.out.println("Screen clear");
//Restart , well.. at least that what i want
t = new Thread(my_run_class);
t.setDaemon(true);
t.start(); //Start Thread
System.out.println("Stoped Thread Started again");
}
}
MyRunableClass.java
package project;
import javafx.application.Platform;
import javafx.scene.control.Button;
public class MyRunableClass implements Runnable
{
private Controller controller;
public MyRunableClass(Controller controller)
{
//Getting FXML Controller
this.controller = controller;
}
// public boolean stop = false;
@Override
public void run()
{
for (String name : ListOfNames.getlist())
{
// if(stop) // Exit for loop if true
// {
// break;
// }
Platform.runLater(new Runnable()
{
@Override
public void run()
{
Button btn = new Button("Button : "+name);
System.out.println(name);
controller.flowPane.getChildren().add(btn);
}
});
try {
Thread.sleep(1); // Wait for half sec this time
} catch (InterruptedException e) { // try catch it needed for some reason
e.printStackTrace();
}
}
}
}
ListOfNames.java
package project;
import java.util.ArrayList;
public class ListOfNames
{
private static ArrayList<String> list_of_names ;
public ListOfNames()
{
list_of_names = new ArrayList<>();
list_of_names.add("A");
list_of_names.add("B");
list_of_names.add("C");
list_of_names.add("D");
list_of_names.add("E");
list_of_names.add("F");
list_of_names.add("G");
list_of_names.add("H");
list_of_names.add("I");
list_of_names.add("J");
list_of_names.add("K");
list_of_names.add("L");
list_of_names.add("M");
list_of_names.add("N");
list_of_names.add("O");
list_of_names.add("P");
list_of_names.add("Q");
list_of_names.add("R");
list_of_names.add("S");
list_of_names.add("T");
list_of_names.add("U");
list_of_names.add("V");
list_of_names.add("W");
list_of_names.add("X");
list_of_names.add("Y");
list_of_names.add("Z");
}
public static ArrayList<String> getlist() {
return list_of_names;
}
}
Window.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.FlowPane?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="413.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="project.Controller">
<children>
<FlowPane fx:id="flowPane" layoutX="2.0" layoutY="61.0" prefHeight="352.0" prefWidth="600.0" style="-fx-border-color: #000000; -fx-border-insets: 1.1; -fx-border-width: 5;" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="61.0" />
<Button layoutX="405.0" layoutY="14.0" mnemonicParsing="false" onAction="#stop_Button" prefHeight="39.0" prefWidth="80.0" text="Stop" />
<Button layoutX="313.0" layoutY="14.0" mnemonicParsing="false" onAction="#start_Button" prefHeight="39.0" prefWidth="80.0" text="Star" />
<Button layoutX="497.0" layoutY="14.0" mnemonicParsing="false" onAction="#clear_Button" prefHeight="39.0" prefWidth="80.0" text="Clean" />
<Button layoutX="40.0" layoutY="14.0" mnemonicParsing="false" onAction="#refresh_Button" prefHeight="39.0" prefWidth="109.0" text="Refresh" />
</children>
</AnchorPane>
我没有阅读您的所有代码,但我将对如何取消和 "restart" 和 Task
进行一般性说明。
首先,不要使用Thread
的suspend
、stop
、resume
方法;他们被弃用是有原因的。
与所有后台任务一样,取消需要该后台任务的开发人员的合作。该任务必须在适当的时候检查它是否已被取消并做出相应的反应。一般是通过查询当前Thread
的中断状态来实现的,但是Task
class继承了FutureTask
更容易使用的isCancelled
方法。
模拟长运行工作的例子:
public class MyTask extends Task<Void> {
@Override
protected Void call() throws Exception {
for (int i = 0; i < 10_000; i++) {
if (isCancelled()) {
break;
}
updateMessage(Integer.toString(i));
Thread.sleep(1L);
updateProgress(i, 10_000);
}
return null;
}
}
您使用 Worker
接口的 cancel
方法取消了 Task
。注意在循环的每次迭代中检查 isCancelled
;当调用 cancel
方法时,Task
将尽早停止。此外,调用 Worker.cancel()
(或 Future.cancel(true)
)将中断 Thread
,这意味着任何可中断的操作(例如 Thread.sleep
)将抛出 InterruptedException
。
您可以通过观察 Task
的属性或添加事件处理程序来对 Task
成功、失败或取消做出反应。
MyTask task = new MyTask();
task.setOnSucceeded(event -> handleSucceededTask());
task.setOnFailed(event -> handleFailedTask());
task.setOnCancelled(event -> handleCancelledTask());
您可以在这些回调中进行清理并根据需要执行 new Task
。请注意,您必须启动一个新的 Task
,因为 Task
是一次性的。