Another main point of this post is to show the different of loading data in various stage. There are three position in the code to load barchart data.
- At position A: call prepareMemInfo() to load barchart data in JavaFX Application Thread, before UI show.
- At position B, call prepareMemInfo() to load barchart data in JavaFX Application Thread, after UI show.
- At position C, start another thread to load barchart data.
In this case, another question rised: in prepareMemInfo(), the file /proc/meminfo is parsed in sequency, but add data to series2 in Application Thread by calling Platform.runLater(). May be it will not in the same sequency. <- I'm not sure here.
Check this video to know the different:
package javafx_meminfo;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Stream;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleFloatProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
*
* @web http://java-buddy.blogspot.com/
*/
public class JavaFX_meminfo extends Application {
final static String FILE_MEMINFO = "/proc/meminfo";
private final TableView<Record> tableMem = new TableView<>();
ObservableList<Record> listRecords = FXCollections.observableArrayList();
XYChart.Series series1 = new XYChart.Series(); //load in Application Thread
XYChart.Series series2 = new XYChart.Series(); //load in Background Thread
final CategoryAxis xAxis = new CategoryAxis();
final NumberAxis yAxis = new NumberAxis();
final BarChart<String, Number> barChart = new BarChart<>(xAxis, yAxis);
@Override
public void start(Stage primaryStage) {
//position A - run in UI Thread, before UI show
//prepareMemInfo();
tableMem.setEditable(false);
TableColumn colMemField = new TableColumn("Field");
colMemField.setMinWidth(150);
colMemField.setCellValueFactory(
new PropertyValueFactory<>("memField"));
TableColumn colMemValue = new TableColumn("Value");
colMemValue.setMinWidth(100);
colMemValue.setCellValueFactory(
new PropertyValueFactory<>("memValue"));
TableColumn colMemUnit = new TableColumn("Unit");
colMemUnit.setMinWidth(50);
colMemUnit.setCellValueFactory(
new PropertyValueFactory<>("memUnit"));
TableColumn colMemQty = new TableColumn("Qty");
colMemQty.setMinWidth(200);
colMemQty.setCellValueFactory(
new PropertyValueFactory<>("memQty"));
tableMem.setItems(listRecords);
tableMem.getColumns().addAll(colMemField,
colMemValue, colMemUnit, colMemQty);
//Create a dummy ProgressBar running
ProgressTask progressTask = new ProgressTask();
ProgressBar progressBar = new ProgressBar();
progressBar.setProgress(0);
progressBar.progressProperty().bind(progressTask.progressProperty());
new Thread(progressTask).start();
//---
VBox vBox = new VBox();
vBox.getChildren().addAll(tableMem, progressBar);
StackPane root = new StackPane();
root.getChildren().add(vBox);
Scene scene = new Scene(root, 500, 250);
primaryStage.setTitle("java-buddy");
primaryStage.setScene(scene);
primaryStage.show();
//Open second window
barChart.setTitle(FILE_MEMINFO);
xAxis.setLabel("Field");
yAxis.setLabel("Qty");
barChart.getData().addAll(series1, series2);
StackPane secondaryLayout = new StackPane();
secondaryLayout.getChildren().add(barChart);
Scene secondScene = new Scene(secondaryLayout, 500, 400);
Stage secondStage = new Stage();
secondStage.setTitle("Second Stage");
secondStage.setScene(secondScene);
//Set position of second window, related to primary window.
secondStage.setX(primaryStage.getX() + 250);
secondStage.setY(primaryStage.getY() + 20);
secondStage.show();
//position B - run in UI Thread, after UI show
//prepareMemInfo();
//position C - run in background Thread
new Thread(BackgroundPrepareMemoInfo).start();
}
public static void main(String[] args) {
launch(args);
}
Runnable BackgroundPrepareMemoInfo = () -> {
prepareMemInfo();
};
private void prepareMemInfo() {
//dummy delay
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(JavaFX_meminfo.class.getName()).log(Level.SEVERE, null, ex);
}
Stream<String> streamMemInfo = readFile(FILE_MEMINFO);
streamMemInfo.forEach((line) -> {
System.out.println(line);
//split one line by whitespace/grouped whitespaces
String[] oneLine = line.split("\\s+");
for (String ele : oneLine) {
System.out.println(ele);
}
System.out.println("---");
String rField = "";
int rMemValue = 0;
String rMemUnit = "";
if (oneLine.length <= 3) {
if (oneLine.length == 3) {
rField = oneLine[0];
rMemValue = Integer.parseInt(oneLine[1]);
rMemUnit = oneLine[2];
} else if (oneLine.length == 2) {
rField = oneLine[0];
rMemValue = Integer.parseInt(oneLine[1]);
rMemUnit = "B";
} else if (oneLine.length == 1) {
rField = oneLine[0];
rMemValue = 0;
rMemUnit = "B";
}
Record record = new Record(
rField, rMemValue, rMemUnit);
listRecords.add(record);
if (Platform.isFxApplicationThread()) {
//It's running in UI Thread
series1.getData().add(new XYChart.Data(record.getMemField(), record.getMemQty()));
} else {
//It's running in background Thread
Platform.runLater(() -> {
series2.getData().add(new XYChart.Data(record.getMemField(), record.getMemQty()));
});
}
}
});
}
private Stream<String> readFile(String filePath) {
Path path = Paths.get(filePath);
Stream<String> fileLines = null;
try {
fileLines = Files.lines(path);
} catch (IOException ex) {
Logger.getLogger(JavaFX_meminfo.class.getName()).log(Level.SEVERE, null, ex);
}
return fileLines;
}
public static class Record {
private final SimpleStringProperty memField;
private final SimpleIntegerProperty memValue;
private final SimpleStringProperty memUnit;
private final SimpleFloatProperty memQty;
private Record(String memField, int memValue, String memUnit) {
this.memField = new SimpleStringProperty(memField);
this.memValue = new SimpleIntegerProperty(memValue);
this.memUnit = new SimpleStringProperty(memUnit);
if (memValue == 0) {
this.memQty = new SimpleFloatProperty(0.0f);
} else if (memUnit.equalsIgnoreCase("MB")) {
this.memQty = new SimpleFloatProperty((float) memValue * 1000000.0f);
} else if (memUnit.equalsIgnoreCase("kB")) {
this.memQty = new SimpleFloatProperty((float) memValue * 1000.0f);
} else {
this.memQty = new SimpleFloatProperty((float) memValue);
}
}
public String getMemField() {
return memField.get();
}
public int getMemValue() {
return memValue.get();
}
public String getMemUnit() {
return memUnit.get();
}
public float getMemQty() {
return memQty.get();
}
}
final int MAX_PROGRESS = 50;
class ProgressTask extends Task<Void>{
@Override
protected Void call() throws Exception {
for (int i = 1; i <= MAX_PROGRESS; i++) {
updateProgress(i, MAX_PROGRESS);
Thread.sleep(200);
}
return null;
}
}
}











