Java FX如何“中途”停止线程并重新启动或销毁它

时间:2018-10-25 08:07:43

标签: java multithreading javafx javafx-8 fxml

无法停止线程 Midway 重新启动添加节点线程。

这就是我得到的

enter image description here

这就是我需要的,每当我按下 刷新按钮

时,我就一遍又一遍地想要这样的东西

干净的屏幕重新启动(例如,A到N顺序正确)

enter image description here

为什么?,所以我可以在刷新之前选择其他列表。

背景故事 (忽略) 从一个月开始,我正在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的类,该类实现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;
    }
}

每当我按下 刷新按钮时,我想停止向流面板添加点头的线程中途enter image description here

使用 flow_panel.getChildren()。clear(); 清洁FlowPane 然后从列表的开头重新开始

enter image description here

特别是 -停止 清洁 -重新启动

如果可以通过服务任务做任何事情,那都很好

2 个答案:

答案 0 :(得分:2)

我没有阅读您所有的代码,但是我将给出有关如何取消和“重新启动” Task的一般说明。

首先,请勿使用suspend的{​​{1}},stopresume方法;他们被淘汰是有原因的。

与所有后台任务一样,取消操作需要所述后台任务开发人员的配合。该任务必须在适当的时间检查它是否已被取消并做出相应的反应。通常,这是通过查询当前Thread的中断状态来完成的,但是Thread类从Task继承了易于使用的isCancelled方法。

模拟长期运行的示例:

FutureTask

您可以使用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; } } 界面的Task方法取消cancel。注意循环的每次迭代中Worker的检查;调用isCancelled方法时,cancel将尽早停止。另外,调用Task(或Worker.cancel())将中断Future.cancel(true),这意味着任何可中断的操作(例如Thread)都将抛出Thread.sleep

您可以通过观察InterruptedException的属性或添加事件处理程序来对Task成功,失败或被取消做出反应。

Task

您可以在这些回调中进行清理并根据需要执行 new MyTask task = new MyTask(); task.setOnSucceeded(event -> handleSucceededTask()); task.setOnFailed(event -> handleFailedTask()); task.setOnCancelled(event -> handleCancelledTask()); 。请注意,您必须启动新的Task,因为Task是一次性使用的。

答案 1 :(得分:0)

我找到了解决问题的方法。现在我的问题是有没有更好的方法来达到相同的结果 因为我正在发黄,这意味着我做错了方法

enter image description here

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>