我正在尝试在JavaFX Interface类中实现一个进度指示器,该类将相应地更新为我的“ Reader”类,该类通过日志进行解析并跟踪其进度。
我目前的方法是创建一个单独的线程来运行Reader(这是因为接口在运行Reader时将变得无响应),并且随着Reader的进展,它将直接更新Interfaces进度指示器。
接口类:
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()”之后,当我检查progressBar的进度时,该值将正确更新。只是没有更新Interface类中的progressBar。
我是多线程新手,不确定我是否正确理解它。我查看了教程和其他示例,但没有找到太多帮助。我会很感激的。
编辑:包括整个类文件以获取更多详细信息。
答案 0 :(得分:0)
您的Reader
类似乎扩展了与您想像的类不同的类。您调用super.progressBar.setProgress()
,它正在调用父类Interface
的进度条来更改它。即使Interface
扩展了GUI
类,progressBar
中的GUI
还是私有的,因此您无法访问它。我建议您在实例化GUI
时将进度条从Reader
类传递到Reader
。
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);
});
}
}
答案 1 :(得分:-2)
如果没有足够的信息来做出明智的猜测,建议您将Thread.sleep()
添加到Reader
线程的run()
实现中。从您发布的内容来看,您的Reader线程可能正在消耗所有可用的处理器时间而没有休息,因此GUI线程永远不会有机会进入并更新显示。
如果添加Thread.sleep()
解决了您发布的问题,则需要确定Reader
线程的适当位置和持续时间,以使其在run()
实现中定期让位。