当前位置: 首页 > 知识库问答 >
问题:

JavaFX进度指示器未跨线程更新

陈项禹
2023-03-14

我试图在我的JavaFX接口类中实现一个进度指示器,它相应地更新到我的“读者”类,该类解析日志并跟踪它所取得的进展。

我目前的方法是创建一个单独的线程来运行Reader(这是因为当运行Reader时,界面会变得无响应),当Reader取得进展时,它将直接更新界面进度指示器。

接口类:

public class Interface extends Application {

public ProgressBar pb = new ProgressBar(0);
public ProgressIndicator pi = new ProgressIndicator(0);

private BorderPane bp = new BorderPane();
private Stage stage = new Stage();
private Scene scene = new Scene(bp, 400, 190);
private Button run = new Button();
private Button browseInputPath = new Button();
private Button browseOutputPath = new Button();
private CheckBox runAutomatically = new CheckBox("Run Automatically");
private TextField inputPath = new TextField();
private TextField outputPath = new TextField();
private HBox InputPath = new HBox(5);
private HBox OutputPath = new HBox(5);
private HBox progress = new HBox(10);
private File configFile = new File("config.txt");
private JFileChooser fc = new JFileChooser(FileSystemView.getFileSystemView().getHomeDirectory());

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

@Override
public void start(Stage arg0) throws Exception {

    initializeConfigFile();
    initializeHBoxes();
    initializeProps();

    bp.setTop(progress);
    bp.setBottom(OutputPath);
    bp.setCenter(InputPath);

    stage.setResizable(false);
    stage.setScene(scene);
    stage.show();

    if ( runAutomatically.isSelected() ) { runReader(); }

}

@SuppressWarnings("deprecation")
private void runReader() {

    run.setDisable(true);
    browseInputPath.setDisable(true);
    browseOutputPath.setDisable(true);
    inputPath.setDisable(true);
    outputPath.setDisable(true);

    Reader reader = new Reader(inputPath.getText(), outputPath.getText());
    Thread t = new Thread(reader, "thread");
    t.start();

    stage.setOnCloseRequest(event -> { t.stop(); });

}

private void writeConfigFile(Boolean runAuto, String inputPath, String outputPath) throws FileNotFoundException {

    PrintWriter printer = new PrintWriter(new FileOutputStream(configFile, false));
    printer.println("RunAutomatically: " + runAuto);
    printer.println("InputDirectory: " + inputPath);
    printer.println("OutputDirectory: " + outputPath);
    printer.close();

}

private void initializeConfigFile() throws IOException {

    if ( !configFile.exists() ) {

        File inputFolder = new File("input");
        File outputFolder = new File("output");
        inputFolder.mkdir();
        outputFolder.mkdir();
        writeConfigFile(false, inputFolder.getAbsolutePath(), outputFolder.getAbsolutePath());

    } 

    Scanner input = new Scanner(configFile);

    while ( input.hasNext() ) {

        if ( input.next().contains("RunAutomatically:") ) {

            String temp = input.next();

            if ( temp.contains("true")) { 

                runAutomatically.setSelected(true);

            } else { runAutomatically.setSelected(false); }
        }

        if ( input.next().contains("InputDirectory:") ) { inputPath.setText(input.next()); }

        if ( input.next().contains("OutputDirectory:") ) { outputPath.setText(input.next()); }

    }

    input.close();
}

private void initializeHBoxes() {

    InputPath.setPadding(new Insets(15, 12, 10, 12 ));
    InputPath.setStyle("-fx-background-color: #336699;");
    InputPath.getChildren().add(inputPath);
    InputPath.getChildren().add(browseInputPath);

    OutputPath.setPadding(new Insets(15, 12, 15, 12 ));
    OutputPath.setStyle("-fx-background-color: #336699;");
    OutputPath.getChildren().add(outputPath);
    OutputPath.getChildren().add(browseOutputPath);

    progress.setPadding(new Insets(15, 12, 15, 12 ));
    progress.setStyle("-fx-background-color: #336699;");
    progress.getChildren().add(run);
    progress.getChildren().add(runAutomatically);

    progress.getChildren().add(pb);
    progress.getChildren().add(pi);

}

private void initializeProps() {

    run.setText("Start");
    run.setPrefSize(75, 40);
    Tooltip runHelper = new Tooltip("Begins process to parse log files. Files are taken from input directory path and completed files are placed in output directory path.");
    Tooltip.install(run, runHelper);
    run.setOnAction(event -> { runReader(); });

    pb.setPrefSize(125, 30);
    Tooltip pbHelper = new Tooltip("Total Transactions Completed for File");
    Tooltip.install(pb, pbHelper);

    pi.setPrefSize(100, 100);
    Tooltip piHelper = new Tooltip("Total Files Completed");
    Tooltip.install(pi, piHelper);

    browseInputPath.setText(" ... ");
    browseInputPath.setPrefSize(75, 30);
    browseInputPath.setOnAction(event -> {

        fc.setDialogTitle("Choose Input Directory");
        fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        int returnValue = fc.showOpenDialog(null);

        if ( returnValue == JFileChooser.APPROVE_OPTION) { inputPath.setText(fc.getSelectedFile().getAbsolutePath()); }

    });

    browseOutputPath.setText(" ... ");
    browseOutputPath.setPrefSize(75, 30);
    browseOutputPath.setOnAction(event -> {

        fc.setDialogTitle("Choose Output Directory");
        fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        int returnValue = fc.showOpenDialog(null);

        if ( returnValue == JFileChooser.APPROVE_OPTION) { outputPath.setText(fc.getSelectedFile().getAbsolutePath()); }

    });

    runAutomatically.setOnAction(e -> { 

        try {

            if ( runAutomatically.isSelected() ) {

                writeConfigFile(true, inputPath.getText(), outputPath.getText()); 

            } else { writeConfigFile(false, inputPath.getText(), outputPath.getText()); }

        } catch (FileNotFoundException e2 ) { e2.printStackTrace(); }

    });

    Tooltip autoRunHelper = new Tooltip("If selected, program will automatically run on program startup.");
    Tooltip.install(runAutomatically, autoRunHelper);

    inputPath.setPrefSize(300, 30);
    Tooltip inputPathHelper = new Tooltip("Input Path Directory");
    Tooltip.install(inputPath, inputPathHelper);

    outputPath.setPrefSize(300, 30);
    Tooltip outputPathHelper = new Tooltip("Output Path Directory");
    Tooltip.install(outputPath, outputPathHelper);  
    }
}

阅读类:

public class Reader extends Interface implements Runnable {

private ArrayList<ArrayList<String>> database;
private String storeInfo;
private String date;
private String inputDirectory;
private String outputDirectory;
private int finalTransactionNumber;
private int firstTransactionNumber;
private int totalTransactions = 0;
private int completedTransactions = 0;
private int totalFiles = 0;
private int completedFiles = 0;

public Reader(String inputDirectory, String outputDirectory) {

    this.inputDirectory = inputDirectory;
    this.outputDirectory = outputDirectory;

}

public void run() {

    try {

        File[] directory = new File(inputDirectory).listFiles();
        totalFiles = directory.length;

        for ( int i = 0; i < totalFiles; i++ ) {

            completedTransactions = 0;
            initializeArrayList(directory[i]);
            storeInfo = retrieveStoreInfo(directory[i]);
            date = retrieveLogDate(directory[i]);

            new File(outputDirectory + "\\" + date).mkdirs();
            File output = new File(outputDirectory + "\\" + date + "\\" + storeInfo + ".txt");

            readFile(directory[i]);
            writeTransactionInfo(output);
            updateFileProgress();

        }

    } catch (FileNotFoundException e) { e.printStackTrace(); } 
}

/**
 * Updates progress bar from extended interface class by calculating completed transactions per file.
 * @throws InterruptedException 
 */
private void updateTransactionProgress() { 

    if ( totalTransactions == 0 ) { super.pb.setProgress(0); }

    completedTransactions++;
    super.pb.setProgress( (completedTransactions + 0.0) / totalTransactions );

    System.out.println(pb.getProgress());
}

/**
 * Updates progress indicator (pie chart) from extended interface class by calculating total completed files.
 */
private void updateFileProgress() {

    if ( totalFiles == 0 ) { super.pi.setProgress(0); }

    completedFiles++;
    super.pi.setProgress( (completedFiles + 0.0) / totalFiles );

}

/**
 * Scans log file to retrieve and save transaction information.
 * Time Complexity: O(n)
 * @param inputFile
 * @throws FileNotFoundException
 * @throws InterruptedException 
 */
private void readFile(File inputFile) throws FileNotFoundException {

        int transactionNumber = firstTransactionNumber;
        Scanner input = new Scanner(inputFile);

        while ( transactionNumber < finalTransactionNumber ) {

            String tempTime = input.next();
            String tempLine = input.nextLine();

            if ( !database.get(0).get(transactionNumber - firstTransactionNumber).equals("-1") && !database.get(1).get(transactionNumber - firstTransactionNumber).equals("-1") && !database.get(2).get(transactionNumber - firstTransactionNumber).equals("-1") && !database.get(3).get(transactionNumber - firstTransactionNumber).equals("-1")) {

                System.out.println("found transaction: " + transactionNumber);
                updateTransactionProgress();
                transactionNumber++;

            } else if ( tempLine.contains("StartTransaction") && tempLine.contains("#" + transactionNumber) ) {

                database.get(0).set(transactionNumber - firstTransactionNumber, tempTime);

            } else if ( tempLine.contains("EndTransaction") && tempLine.contains("#" + transactionNumber) ) {

                database.get(1).set(transactionNumber - firstTransactionNumber, tempTime);

            } else if ( tempLine.contains("FTransType=") && tempLine.contains("" + transactionNumber) ) {

                if ( database.get(2).get(transactionNumber - firstTransactionNumber).equals("-1") ) {

                    database.get(2).set(transactionNumber - firstTransactionNumber, (parseTransactionType(tempLine)));

                } else {

                    database.get(3).set(transactionNumber - firstTransactionNumber, (parseTransactionType(tempLine)));

                }

            } else if ( tempLine.contains("PrePayTrsNumber=") && tempLine.contains("#" + transactionNumber)) {

                database.get(4).set(transactionNumber - firstTransactionNumber, "Prepaid");

            } else if ( !input.hasNextLine() ) {

                if ( database.get(1).get(transactionNumber - firstTransactionNumber).equals("-1") && database.get(3).get(transactionNumber - firstTransactionNumber).equals("-1") ) {

                    database.get(1).set(transactionNumber - firstTransactionNumber, "");
                    database.get(3).set(transactionNumber - firstTransactionNumber, "");

                } else if ( database.get(3).get(transactionNumber - firstTransactionNumber).equals("-1") ) {

                    database.get(3).set(transactionNumber - firstTransactionNumber, "");

                }

                input.close();
                input = new Scanner(inputFile);
            }
        }

        input.close();
    }

/**
 * Creates and fills database ArrayList which holds individual ArrayLists for each type of transaction information.
 * Also instantiates variables which assist the log scanning process.
 * @param inputFile
 * @throws FileNotFoundException
 */
private void initializeArrayList( File inputFile ) throws FileNotFoundException {

    firstTransactionNumber = retrieveFirstTransactionNumber(inputFile);
    finalTransactionNumber = retrieveFinalTransactionNumber(inputFile, firstTransactionNumber);
    totalTransactions = (finalTransactionNumber - firstTransactionNumber);

    System.out.println(firstTransactionNumber);
    System.out.println(finalTransactionNumber);

    //database[0] = startTimes; database[1] = endTimes; database[2] = FTransType1; database[3] = FTransType2; database[4] = isPrepaid
    database = new ArrayList<ArrayList<String>>(5);

    for ( int i = 0; i < 5; i++ ) { database.add(new ArrayList<String>(totalTransactions)); }

    for ( int i = 0; i < totalTransactions; i++ ) {

        database.get(0).add("-1");
        database.get(1).add("-1");
        database.get(2).add("-1");
        database.get(3).add("-1");
        database.get(4).add("");

    }
}

/**
 * Parses strings from transaction log to retrieve transaction type.
 * @param tempLine
 * @return transaction type
 */
private String parseTransactionType(String tempLine) {

    if ( tempLine.contains("Sale")) { 

        return "Sale"; 

    } else if ( tempLine.contains("Void")) {

        return "Void";

    } else if ( tempLine.contains("PayOut")) {

        return "PayOut";

    } else if ( tempLine.contains("PayIn")) {

        return "PayIn";

    } else if ( tempLine.contains("Drop")) {

        return "Drop";

    } else if ( tempLine.contains("CloseBank")) {

        return "CloseBank";

    } else if ( tempLine.contains("OpenBank")) {

        return "OpenBank";

    } else if ( tempLine.contains("Refund")) {

        return "Refund";

    } else { return ""; }
}

/**
 * Writes transaction information withheld in the database ArrayList to output file.
 * @param outputFile
 * @throws FileNotFoundException
 */
private void writeTransactionInfo(File outputFile) throws FileNotFoundException {

    try {

        PrintWriter writer = new PrintWriter(new FileOutputStream(outputFile, false));
        writer.close();

        writer = new PrintWriter(new FileOutputStream(outputFile, true));

        for ( int i = 0; i < database.get(0).size(); i++ ) {

                writer.println(firstTransactionNumber + i + "," + database.get(0).get(i) + "," + database.get(1).get(i) + "," + database.get(2).get(i) + ","
                + database.get(3).get(i) + "," + database.get(4).get(i) + "," + storeInfo + "," + date);

        }

        writer.close();

    } catch (IOException e) {

        e.printStackTrace();

    }
}

/**
 * Used to initialize transaction number variable; Locates first transaction number used.
 * @param inputFile
 * @return transaction number
 * @return -1 if transaction number is not found
 * @throws FileNotFoundException
 */
private int retrieveFirstTransactionNumber(File inputFile) throws FileNotFoundException {

    Scanner input = new Scanner(inputFile);

    while ( input.hasNext() ) {

        String temp = input.next();

        if ( temp.contains("StartTransaction") ) {

            temp = input.next();

            if ( temp.equals("Trs") ) {

                temp = input.next();
                input.close();
                temp = temp.substring(1, temp.length());
                return Integer.parseInt(temp);

            }
        }
    }

    input.close();
    return -1;
}

/**
 * Returns last transaction number in log; used to determine when file reader should stop.
 * @param inputFile
 * @param firstTransactionNumber
 * @return -1 if not found
 * @throws FileNotFoundException
 */
private int retrieveFinalTransactionNumber(File inputFile, int firstTransactionNumber) throws FileNotFoundException {

    Scanner input = new Scanner(inputFile);
    String temp = null;
    int finalTransactionNumber = -1;

    while ( input.hasNextLine() ) {

        temp = input.nextLine();

        if ( temp.contains("#" + Integer.toString(firstTransactionNumber).substring(0, 1)) && temp.contains("StartTransaction")) {

            finalTransactionNumber = Integer.parseInt(temp.substring(87, 94));

        }
    }

    input.close();
    return finalTransactionNumber;
}

/**
 * Retrieves register ID and store number
 * @param inputFile
 * @return computerName
 * @throws FileNotFoundException
 */
private String retrieveStoreInfo(File inputFile) throws FileNotFoundException {

    Scanner input = new Scanner(inputFile);
    String computerName = null;

    while ( computerName == null && input.hasNext() ) {

        String temp = input.next();

        if ( temp.startsWith("SPR") ) { computerName = temp; }
    }

    input.close();
    return computerName;
}

/**
 * Retrieves date of log file
 * @param inputFile
 * @return date
 * @throws FileNotFoundException
 */
private String retrieveLogDate(File inputFile) throws FileNotFoundException {

    Scanner input = new Scanner(inputFile);
    String temp = null;

    while ( input.hasNext() ) {

        temp = input.next();

        if ( temp.contains("Date:")) {

            temp = input.next().replace('/', '-');
            input.close();
            return temp;

        }
    }

    input.close();
    return "";
}

}

当我在每次调用updateTransactionProgress()后检查进度栏时,该值正在正确更新。它只是没有更新Interface类中的进步栏。

我是多线程新手,不确定自己是否理解正确。我查阅了教程和其他示例,但没有找到多少帮助。我会很感激你的帮助。

编辑:包含整个类文件以获取更多详细信息。

共有2个答案

金高飞
2023-03-14

如果没有足够的信息来做出明智的猜测,我建议你添加一个线程。sleep()读卡器线程的运行()实现。从你发布的内容来看,你的阅读器线程很可能在不Rest的情况下消耗了所有可用的处理器时间,因此GUI线程永远没有机会跳入并更新显示。

如果添加Thread.sleep()解决了您发布的问题,您需要为您的Reader线程确定一个合适的位置和持续时间,以便在您的run()实现中定期让位。

吴展
2023-03-14

看起来你的阅读器类扩展了一个与你想象中不同的类。你叫超级。progressBar。setProgress(),它正在调用父类接口的进度条来更改它。即使Interface扩展了GUI类,GUI中的progressBar也是私有的,因此您无法访问它。我建议您在实例化阅读器时,将进度条从GUI类传递到阅读器

public class GUI extends Application {

    private ProgressBar _progressBar = new ProgressBar(0);

    // Methods which display GUI w/ progressBar

    private void runReader() {
      // progressBar should be instantiated by now, of course
      Reader reader = new Reader(_progressBar, "input Path", "output Path");
      Thread t = new Thread(reader, "reader thread");
      t.start();
    }
}

public class Reader extends Interface implements Runnable {
     private final ProgressBar _progressBar = bar;

     public void Reader(ProgressBar bar, String in, String out){
         _progressBar = bar;
         // Rest of constructor here
     }
    //Main processing methods that call 'updateTransactionProgress()'

    private void updateTransactionProgress() {

        if ( totalTransactions == 0 ) { super.pb.setProgress(0); }
        completedTransactions++;.

        // Call to Platform.runLater() to run the update on the JavaFX Application Thread
        Platform.runLater(() -> {
            _progressBar.setProgress((completedTransactions + 0.0) / 
            totalTransactions);
        });
    }
}
 类似资料:
  • 主要内容:创建ProgressIndicator进度指示器()以动态更改饼图的形式显示JavaFX中的操作进度。以下代码显示如何使用不确定值创建。 上面的代码生成以下结果。 创建ProgressIndicator 以下代码通过传递值来创建。 可以使用空构造函数创建没有参数的进度指示器。然后可以使用方法分配值。 如果无法确定进度,可以在不确定模式下设置进度控制,直到确定任务的长度。 以下代码显示如何创建一个完成25%的。 上面的代码生成以下结果。

  • 我搜索了al堆栈溢出,我只找到了进度条。就像windows中的进度条和...我正在寻找一个多步骤进度条。就像我们在网上购物网站上存档信息时所拥有的一样。例如,它有4个步骤。1-选择产品2-填写信息...然后在每一步中,所有这些都是打开的,直到我们现在在那一步。下一步就走了。JavaFX中有thrick的插件吗?

  • 我正在创建一个JavaFX桌面应用程序,我在上面模拟一些工作负载。我希望应用程序有一个动态更新的进度指示器(随着时间的推移),以显示加载过程是如何进行的。这是我的应用程序类: 这是我的预加载程序类: 另外,我需要说的是,我已经检查了这两个问题(预加载程序中的progressbar不更新和javafx预加载程序不更新进度),但没有找到解决问题的方法。 非常感谢您抽出时间。

  • 问题内容: 我的应用程序中出现JavaFX(jdk 1.8.0_91)上的一个讨厌的错误,该错误中显示并更新了几个进度条(随机或同时显示)。有时,尤其是在填充进度条时(它具有进度条的样式类),但有时甚至一无所获,软件块和该跟踪出现了几次(并非总是相同的数字,而是最后一次)一次是27次): 然后在这27条痕迹之后跟随着大量的此消息: 线程“ JavaFX应用程序线程”中的异常java.lang.Ar

  • 问题内容: 我同时使用Javafx和线程,并且遇到了这个问题,我制作了一个按钮,然后单击该按钮(使用事件处理程序)时,我做了一个for循环,将按钮更改为1,2,3,4 ,5,然后在每个中间延迟一秒钟。像倒计时! 但是发生的事情是延迟了5秒钟,并将按钮的文本更改为5。 问题是我希望看到它在1到5之间变化,但我看到的只是在5秒延迟结束时为5。我认为它会更改按钮文本,但看不到。我可能与类中的方法有关。

  • 我同时使用Javafx和线程,我经常遇到这个问题,我制作了一个按钮,然后当单击按钮时(使用事件处理程序),我制作了一个for循环,将按钮更改为1、2、3、4、5,然后在每个按钮中间延迟一秒钟。就像倒计时一样! 但实际情况是,它会延迟5秒钟,并将按钮的文本更改为5。 问题是我想看到它在1到5之间变化,但我看到的只是5秒延迟结束时的5。我假设它会更改按钮文本,但我看不到它。我可能不得不处理<代码>。在