【问题标题】:Javafx task/thread does not startJavafx 任务/线程未启动
【发布时间】:2017-12-17 12:10:46
【问题描述】:

我有一个 JavaFX 程序,我想在其中导入一个文件并从该文件中读取所有内容(应该是 .txt)并将其写入一个字符串,以便我可以处理它。因为文件有时很大,让我的程序说“无响应”之类的东西,我想添加一个 ProgressBar,以显示当前的进度并阻止程序崩溃。

起初,我只是在对话框中添加了一个 ProgressBar,它会根据绑定打开和更新。但是 GUI 没有更新,所以我发现我必须做一个新线程,它在后台运行,所以我的程序不会停止响应。所以我把所有东西都打包到一个Task中,用一个Thread开始这个任务,但是现在带有ProgressBar的Dialog都没有出现,所以我调试了一下,发现程序甚至不做任务,就像, 不做任何事情就过去了。

这是我当前的代码,我希望任何人都可以帮助我解决我的问题或向我解释任务/线程:

我的处理程序:

package application.handler;

import application.data.KTChat;
import application.gui.MyRootPane;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Button;
import javafx.scene.control.MenuItem;
import javafx.stage.FileChooser;
import javafx.stage.Stage;

public class MyHandler implements EventHandler<ActionEvent> {
    private MyRootPane mp;
    private FileChooser fc;
    private Stage primaryStage;
    private KTChat kt;

    public MyHandler(MyRootPane mp, Stage primaryStage) {
        this.mp = mp;
        fc = new FileChooser();
        fc.getExtensionFilters().add(new FileChooser.ExtensionFilter("Text files (*.txt)", "*.txt"));
        this.primaryStage = primaryStage;
        kt = new KTChat(mp);
    }

    @Override
    public void handle(ActionEvent event) {
            String mdata = ((MenuItem)(event.getSource())).getId();
            if(mdata.equalsIgnoreCase("import")) {
                kr.readFile(fc.showOpenDialog(primaryStage));
            }
    }
    public KTChat getKT() {
        return kt;
    }
}

MyRootPane(我的 GUI):

package application.gui;

import java.io.File;

import application.handler.MyHandler;
import javafx.beans.property.DoubleProperty;
import javafx.collections.ObservableList;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextArea;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class MyRootPane extends BorderPane {
    private TextArea eingabe = new TextArea();
    private TextArea ausgabe = new TextArea();
    private MenuBar mb = new MenuBar();
    private Menu m2 = new Menu("Settings");
    private MenuItem mi4 = new MenuItem("Import chat");
    private Stage primaryStage;
    private MyHandler mh;
    private FortschrittDialog fd = new FortschrittDialog();

    public MyRootPane(Stage primaryStage) {
        this.primaryStage = primaryStage;
        mh = new MyHandler(this, primaryStage);
        initSettings();
        setTop(mb);
        setCenter(eingabe);
        setBottom(ausgabe);
    }
    public void initSettings() {
        ausgabe.setEditable(false);
        eingabe.setPrefHeight(500);
        ausgabe.setPrefHeight(500);

        mi4.setId("import");
        mi4.setOnAction(mh);
        m2.getItems().add(mi4);
        mb.getMenus().add(m2);
    }
    public void eingabeSetText(String eingabe) {
        this.eingabe.setText(eingabe);
    }
    public String eingabeGetText() {
        return eingabe.getText();
    }
    public void startFortschrittDialog() {
        fd.show();
    }
    public void endFortschrittDialog() {
        fd.close();
    }
    public void isFortschrittDialogCompleted() {
        if(fd.isCompleted()) endFortschrittDialog();
    }
    public DoubleProperty progressP() {
        return fd.getPBProgressProperty();
    }
}

然后我的 KTChat 应该是最初构建字符串的位置:

package application.data;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

import application.gui.MyRootPane;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableDoubleValue;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;

public class KTChat {

    private String chat;

    private MyRootPane mp;

    public KTChat(MyRootPane mp) {
        this.mp = mp;
    }
    public void setChat(String eingabeGetText) {
        this.chat = eingabeGetText;
        getChat();
    }
    public void readFile(File chat) {
        Task<Void> task = new Task<Void>() {

            @Override
            protected Void call() throws Exception {
                if(chat.getName().contains("KakaoTalk_")) {
                    mp.startFortschrittDialog();
                    mp.setFortschritt(-1.0f);
                    String s = "";
                    String gesamt = "";
                    double laenge = 0;
                    try(BufferedReader brCount = new BufferedReader(new FileReader(chat))) {
                        while((s=brCount.readLine())!=null) {
                            laenge++;
                        }
                    } catch (IOException e) {
                        System.out.println("Fehler beim zählen");
                    }
                    double momentanErreicht = 0;
                    try(BufferedReader br = new BufferedReader(new FileReader(chat))) {
                        while((s=br.readLine())!=null) {
                            momentanErreicht++;
                            updateProgress(momentanErreicht, laenge);
                            s = s.replace("ß", "ß");
                            s = s.replace("ö", "ö");
                            s = s.replace("ü", "ü");
                            s = s.replace("ä", "ä");
                            s = s.replace("Ä", "Ä");
                            s = s.replace("Ü", "Ü");
                            s = s.replace("Ö", "Ö");
                            gesamt += s+"\n";
                        }
                    } catch (FileNotFoundException e1) {
                        System.out.println("File not found");
                    } catch (IOException e2) {
                        System.out.println("IOException");
                    }
                    mp.isFortschrittDialogCompleted();
                    mp.eingabeSetText(gesamt);
                    setChat(mp.eingabeGetText());
                    getChat();
                } else mp.mhNichtPassendesFile();
                return null;
            }
        };
        mp.progressP().bind(task.progressProperty());
        Thread th = new Thread(task);
        th.setDaemon(true);
        th.start();
    }

我的 ProgressBar 所在的对话框:

package application.gui;

import javafx.beans.property.DoubleProperty;
import javafx.scene.control.Dialog;
import javafx.scene.control.ProgressBar;

@SuppressWarnings("rawtypes")
public class FortschrittDialog extends Dialog {

    private ProgressBar pb = new ProgressBar();

    public FortschrittDialog() {
        pb.setPrefWidth(500);
        pb.setProgress(-1f);

        getDialogPane().setContent(pb);
    }
    public DoubleProperty getPBProgressProperty() {
        return pb.progressProperty();
    }
    public boolean isCompleted() {
        if(pb.getProgress()==1.0) return true;
        else return false;
    }
}

最后但并非最不重要的是 Main 类:

package application;

import application.gui.MyRootPane;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;


public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {
            MyRootPane root = new MyRootPane(primaryStage);
            Scene scene = new Scene(root,1280,720);
            scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
            primaryStage.setTitle("KT-Chat-Statistics V1.1");
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

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

我尝试包含与问题相关的所有内容,您应该可以复制粘贴代码来自己测试它。我真的不明白为什么它不起作用。

【问题讨论】:

  • 这里可能有很多问题,一个例子是JavaFX系统调用了start方法,所以我不确定你为什么要显式调用start。另外,为什么在 KTChat 和 ImportFile 中重复代码?
  • 为了获得最好的帮助,通常最好提供minimal reproducible example,有人可以复制和粘贴,无需修改,执行和复制问题。此类代码通常远小于您问题中粘贴的代码。
  • 感谢您的提示,我想展示这两种方法,一种在扩展应用程序的类中,另一种在“普通”类中,因为我在此站点上的另一个问题中读到任务必须在一个类中,由 Application 扩展,我不确定这是对还是错
  • 错了,Task是一个单独的类,不需要在扩展Application的类中创建或定义。在您的问题中显示这两种方法会令人困惑,因为当您包含冗余代码时,读者很难弄清楚您在做什么。
  • 谢谢,我删除了不必要的附加代码,希望你现在能更好地理解我的意思

标签: java multithreading user-interface task


【解决方案1】:

我发现了问题。对于遇到同样问题或只是想知道的其他人,这是我做错的地方:

您不能在后台任务期间调用 JavaFX-Thread-Methods,因此不会执行到达任务之外的每个方法(我认为只有 mp.-methods)。 因此,我制作的 Dialog 中的 ProgressBar 将起作用,但不会显示 Dialog,因为显示 Dialog 的方法位于 MyRootPane-Class 中。而且我们现在知道,JavaFX-Thread-Methods 不能在后台任务期间执行。

所以,下面是代码中的确切变化,因此它可以运行: 您必须将所有 mp.-methods 放在任务之外,因此在通过线程启动任务之前,只需打开那里的对话框,例如:

        mp.progressP().bind(task.progressProperty());
        mp.startFortschrittDialog();
        Thread th = new Thread(task);
        th.setDaemon(true);
        th.start();

我希望这清楚易懂,谢谢大家的时间。

【讨论】:

    猜你喜欢
    • 2014-05-04
    • 1970-01-01
    • 2011-04-21
    • 1970-01-01
    • 2016-08-15
    • 1970-01-01
    • 2018-07-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多