How to create Stacked bar chart Date time Category - java

I expect to create Status chart like this
However I cant XAXis Category was rendered incorrectly.
Here is my code I studied from JFreeChart - horizontal stacked bar chart with date axis
private static final String STANDBY_SERIES = "STANDBY";
private static final String HEATING_SERIES = "HEATING";
private static final String HOLDING_SERIES = "HOLDING";
private static final String COOLING_SERIES = "COOLING";
private static final String LOWERING_SERIES = "LOWERING";
private static final int STANDBY_SERIES_INDEX = 0;
private static final int HEATING_SERIES_INDEX = 1;
private static final int HOLDING_SERIES_INDEX = 2;
private static final int COOLING_SERIES_INDEX = 3;
private static final int LOWERING_SERIES_INDEX = 4;
private static final Color STANDBY_COLOR = Color.DARK_GRAY;
private static final Color HEATING_COLOR = Color.ORANGE;
private static final Color HOLDING_COLOR = Color.YELLOW;
private static final Color COOLING_COLOR = Color.CYAN;
private static final Color LOWERING_COLOR = Color.GREEN;
ArrayList<EventStatus> testData = null;
CategoryPlot plot;
private Long Datetolong(String date)
{
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm");
Date inputDate = null;
try {
inputDate = simpleDateFormat.parse(date);
System.out.println(inputDate.getTime());
} catch (ParseException e) {
e.printStackTrace();}
return inputDate.getTime();
}
public StackedTimeBarChart(String title) {
super(title);
// set up some test data
initData();
// set the start and end date of the chart
plot = new CategoryPlot();
plot.setRangeAxisLocation(AxisLocation.BOTTOM_OR_RIGHT);
plot.setOrientation(PlotOrientation.HORIZONTAL);
// create dataset
CategoryDataset dataset = createDataset();
// create the axis
CategoryAxis catAxis = new CategoryAxis();
DateAxis dateAxis = new DateAxis();
dateAxis.setVerticalTickLabels(true);
//dateAxis.setTickUnit(new DateTickUnit(DateTickUnitType.HOUR, 1));
dateAxis.setDateFormatOverride(new SimpleDateFormat("dd/MM/yyyy HH:mm"));
// set up the renderer
StackedBarRenderer rend = new StackedBarRenderer();
//rend.setBase(chartRange.getLowerBound());
rend.setSeriesPaint(STANDBY_SERIES_INDEX, STANDBY_COLOR);
rend.setSeriesPaint(HEATING_SERIES_INDEX, HEATING_COLOR);
rend.setSeriesPaint(HOLDING_SERIES_INDEX, HOLDING_COLOR);
rend.setSeriesPaint(COOLING_SERIES_INDEX, COOLING_COLOR);
rend.setSeriesPaint(LOWERING_SERIES_INDEX, LOWERING_COLOR);
// set up the plot
plot.setDataset(dataset);
plot.setDomainAxis(catAxis);
plot.setRangeAxis(dateAxis);
plot.setRenderer(rend);
// create the chart and add it
JFreeChart chart = new JFreeChart("", JFreeChart.DEFAULT_TITLE_FONT, plot, true);
ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new Dimension(600, 450));
setContentPane(chartPanel);
}
private CategoryDataset createDataset() {
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
Date chartStartDate = new Date(testData.get(0).getTime());
Date chartEndDate = new Date(testData.get(testData.size() - 1).getTime());
Range chartRange = new Range(chartStartDate.getTime(), chartEndDate.getTime());
if (testData != null) {
for (int i = 0; i < testData.size(); i++) {
// is there data?
if (testData.size() > 0) {
for (int j = 0; j < testData.size(); j++) {
EventStatus es = testData.get(j);
long eventTime = es.getTime();
int status = es.getStatus();
String name = es.getName();
// if data event time is in the range of the chart then show it
// THIS DOES NOT WORK PROPERLY!!!!
if (eventTime >= chartStartDate.getTime() && eventTime < chartEndDate.getTime()) {
// create series and categories
if (es.getStatus() == STANDBY_SERIES_INDEX) {
dataset.addValue(new Double(es.getTime()), STANDBY_SERIES, es.getName());
} else if (es.getStatus() == HEATING_SERIES_INDEX) {
dataset.addValue(new Double(es.getTime()), HEATING_SERIES, es.getName());
} else if (es.getStatus() == HOLDING_SERIES_INDEX) {
dataset.addValue(new Double(es.getTime()), HOLDING_SERIES, es.getName());
} else if (es.getStatus() == COOLING_SERIES_INDEX) {
dataset.addValue(new Double(es.getTime()), COOLING_SERIES, es.getName());
} else if (es.getStatus() == LOWERING_SERIES_INDEX) {
dataset.addValue(new Double(es.getTime()), LOWERING_SERIES, es.getName());
} else {
dataset.addValue(chartRange.getUpperBound() - chartRange.getLowerBound(), STANDBY_SERIES, es.getName());
}
} else {
continue;
}
}
}
}
} else {
plot.setNoDataMessage("NO DATA AVAILABLE");
}
return dataset;
}
public static void main(String[] args) {
StackedTimeBarChart demo = new StackedTimeBarChart("demo");
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
}
private void initData() {
testData = new ArrayList<EventStatus>();
testData.add(new EventStatus("Mach-1", Datetolong("03/04/2020 08:00"), 1));
testData.add(new EventStatus("Mach-1",Datetolong("03/04/2020 09:00"), 2));
testData.add(new EventStatus("Mach-1", Datetolong("03/04/2020 09:20"), 4));
testData.add(new EventStatus("Mach-1", Datetolong("03/04/2020 10:00"), 3));
}
// Chart object class that hold category, event time and status
private class EventStatus {
private String name;
private long time;
private int status;
public EventStatus(String name, long time, int status) {
this.name = name;
this.time = time;
this.status = status;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
}

Related

JFreeChart - Can't see plot unless I zoom in

I have a Jfreechart which is plotting some mock real-time data. When I have my domain axis set to auto, the data can be seen updating every second. However, I wish to plot the data over a wider range (say the whole day). When I change the range, I am then unable to see the plot unless I zoom in.
Once zoomed in, the line does not cover the whole graph, but only a portion. This line then moves across the graph instead of growing/drawing along it
/** #see http://stackoverflow.com/questions/5048852 */
public class DTSCTest extends ApplicationFrame {
private static final String TITLE = "Dynamic Series";
private static final String START = "Start";
private static final String STOP = "Stop";
private static final float MINMAX = 100;
private static final int COUNT = 10;
private static final int FAST = 1000;
private static final int SLOW = FAST * 5;
private static final Random random = new Random();
private double gateStart = ThreadLocalRandom.current().nextInt(0, 101);
private boolean returning = false;
private Timer timer;
public DTSCTest(final String title) {
super(title);
final DynamicTimeSeriesCollection dataset =
new DynamicTimeSeriesCollection(1, COUNT, new Second());
Date date = new Date();
dataset.setTimeBase(new Second(date));
float[] gateStartLoad = new float[1];
gateStartLoad[0] = (float)gateStart;
dataset.addSeries(gateStartLoad, 0, "Longwall Data");
JFreeChart chart = createChart(dataset);
final JComboBox combo = new JComboBox();
combo.addItem("Fast");
combo.addItem("Slow");
combo.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if ("Fast".equals(combo.getSelectedItem())) {
timer.setDelay(FAST);
} else {
timer.setDelay(SLOW);
}
}
});
this.add(new ChartPanel(chart), BorderLayout.CENTER);
JPanel btnPanel = new JPanel(new FlowLayout());
btnPanel.add(combo);
this.add(btnPanel, BorderLayout.SOUTH);
timer = new Timer(FAST, new ActionListener() {
float[] newData = new float[1];
#Override
public void actionPerformed(ActionEvent e) {
if(gateStart == 100){
returning = true;
}else if(gateStart == 0){
returning = false;
}
if(returning){
gateStart--;
}else{
gateStart++;
}
newData[0] = (float)gateStart;
dataset.advanceTime();
System.out.println(dataset.getNewestTime());
dataset.appendData(newData);
}
});
}
private JFreeChart createChart(final XYDataset dataset) {
final JFreeChart result = ChartFactory.createTimeSeriesChart(
TITLE, "hh:mm:ss", "Shearer Position", dataset, true, true, false);
final XYPlot plot = result.getXYPlot();
DateAxis domain = (DateAxis)plot.getDomainAxis();
Calendar calendar = Calendar.getInstance();
calendar.set(2021, 0, 6);
System.out.println(new Date());
System.out.println(calendar.getTime());
domain.setRange(new Date(), calendar.getTime());
domain.setDateFormatOverride(new SimpleDateFormat("HH:mm:ss"));
ValueAxis range = plot.getRangeAxis();
range.setRange(0, 100);
return result;
}
public void start() {
timer.start();
}
public static void main(final String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
DTSCTest demo = new DTSCTest(TITLE);
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
demo.start();
}
});
}
}
How do I make it so that the line is continuous (shows every observed point of data in the series), and how do I make it visible when I manually set the range
I removed domain.setRange(new Date(), calendar.getTime()); and changed nMoments in my DynamicTimeSeriesCollection(1, COUNT, new Second());, making COUNT a multiple of 60 and increasing its value. My x-axis now properly shows time however the plot is not continuous, it disappears after a time

JFreeChart - XYLineAndShapeRenderer getItemLineVisible() not working

I'm simulating dummy real-time data using DynamicTimeSeriesCollection, like this. During random intervals, the data being passed to the plot should 'dropout' to simulate a network connection loss. At this point, this plot should stop drawing and only start plotting the data after the dropout has subsided.
I subclassed XYLineAndShapeRenderer and overrode the getItemLineVisible() method:
#Override
public boolean getItemLineVisible(int series, int item){
if(offline){
return false;
}else{
return true;
}
}
However when offline is true, all points are still being drawn on the graph.
public class Test extends ApplicationFrame {
private static final String TITLE = "Dynamic Series";
private static final String START = "Start";
private static final String STOP = "Stop";
private static final int COUNT = 1000*60;
private static final int FAST = 1; //1000/FAST = occurrences per second real time
private static final int REALTIME = FAST * 1000;
private static final Random random = new Random();
private static final double threshold = 35;
private double gateStart = ThreadLocalRandom.current().nextInt(0, 101);
private boolean returning = false;
private boolean offline = false;
private Timer timer;
private Calendar startDate;
private static final int simulationSpeed = 1000/FAST;
private final TimeSeries seriesA = new TimeSeries("A");
public Test(final String title) throws ParseException {
super(title);
SimpleDateFormat formatter = new SimpleDateFormat("dd/mm/yyyy HH:mm", Locale.ENGLISH);
PriceParser parser = new PriceParser();
List<List<String>> priceData = parser.parse();
Date date = formatter.parse(priceData.get(0).get(0));
startDate = Calendar.getInstance();
startDate.setTime(date);
Calendar timeBaseStartDate = Calendar.getInstance();
timeBaseStartDate.setTime(startDate.getTime());
timeBaseStartDate.add(Calendar.SECOND, -COUNT);
final TimeSeriesCollection dataset = new TimeSeriesCollection();
dataset.addSeries(this.seriesA);
JFreeChart chart = createChart(dataset);
final JComboBox combo = new JComboBox();
combo.addItem("Fast");
combo.addItem("Real-time");
combo.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if ("Fast".equals(combo.getSelectedItem())) {
timer.setDelay(FAST);
} else {
timer.setDelay(REALTIME);
}
}
});
JFrame frame = new JFrame("Test");
JLabel label = new JLabel("Network connectivity lost.");
this.add(new ChartPanel(chart), BorderLayout.CENTER);
JPanel btnPanel = new JPanel(new FlowLayout());
btnPanel.add(combo);
JPanel test = new JPanel();
test.add(label);
this.add(btnPanel, BorderLayout.SOUTH);
// frame.add(btnPanel);
//frame.add(test);
timer = new Timer(FAST, new ActionListener() {
Date timeToCheck = formatter.parse(priceData.get(0).get(0));
Calendar pauseResume = Calendar.getInstance();
Calendar offlineTime = Calendar.getInstance();
boolean paused = false;
boolean waiting = false;
//boolean offline = false;
double currentPrice;
float[] newData = new float[1];
PopupFactory pf = PopupFactory.getSharedInstance();
Popup popup;
#Override
public void actionPerformed(ActionEvent e) {
Date datasetTime = new Date();
if(offline){
System.out.println("Offline: "+offlineTime.getTime());
System.out.println("Current: "+datasetTime);
if(offlineTime.getTime().compareTo(datasetTime) == 0){
offline = false;
System.out.println("Im no longer offline");
popup.hide();
}
}
if(ThreadLocalRandom.current().nextInt(0, 1001) > 999 && !offline){
offline = true;
offlineTime.setTime(datasetTime);
offlineTime.add(Calendar.SECOND, ThreadLocalRandom.current().nextInt(1, 5)*10);
// dataset.addValue(0, 0, null);
popup = pf.getPopup(btnPanel, label, 900, 300);
popup.show();
}
if(timeToCheck.compareTo(datasetTime) == 0){
currentPrice = Double.valueOf(priceData.get(0).get(1));
paused = currentPrice >= threshold;
priceData.remove(0);
try {
timeToCheck = formatter.parse(priceData.get(0).get(0));
} catch (ParseException ex) {
ex.printStackTrace();
}
}
if(!paused) {
if (Math.round(gateStart) * 10 / 10.0 == 100d) {
returning = true;
} else if (Math.round(gateStart) * 10 / 10.0 == 0) {
returning = false;
}
if (returning) {
gateStart -= 0.1d;
} else {
gateStart += 0.1d;
}
}else{
if(datasetTime.compareTo(pauseResume.getTime()) == 0 && currentPrice < threshold){
paused = false;
waiting = false;
}else{
if(Math.round(gateStart)*10/10.0 == 0 || Math.round(gateStart)*10/10.0 == 100){
if(!waiting){
pauseResume.setTime(datasetTime);
pauseResume.add(Calendar.SECOND, 120);
}
waiting = true;
}else{
if(Math.round(gateStart)*10/10.0 >= 50){
gateStart += 0.1d;
}else if(Math.round(gateStart)*10/10.0 < 50){
gateStart -= 0.1d;
}
}
}
}
newData[0] = (float)gateStart;
seriesA.addOrUpdate(new Second(), gateStart);
}
});
}
private JFreeChart createChart(final XYDataset dataset) {
final JFreeChart result = ChartFactory.createTimeSeriesChart(
TITLE, "Time", "Shearer Position", dataset, true, true, false);
final XYPlot plot = result.getXYPlot();
plot.setDomainZeroBaselineVisible(false);
XYLineAndShapeRendererTest renderer = new XYLineAndShapeRendererTest(true, false);
plot.setRenderer(renderer);
DateAxis domain = (DateAxis)plot.getDomainAxis();
Calendar endDate = Calendar.getInstance();
endDate.setTime(new Date());
endDate.add(Calendar.HOUR_OF_DAY, 12);
System.out.println(new Date());
System.out.println(endDate.getTime());
domain.setRange(new Date(), endDate.getTime());
domain.setTickUnit(new DateTickUnit(DateTickUnitType.HOUR, 1));
domain.setDateFormatOverride(new SimpleDateFormat("HH:mm"));
ValueAxis range = plot.getRangeAxis();
range.setRange(0, 100);
return result;
}
private class XYLineAndShapeRendererTest extends XYLineAndShapeRenderer {
private boolean drawSeriesLineAsPath;
public XYLineAndShapeRendererTest(boolean line, boolean shapes){
super(line, shapes);
}
#Override
public Paint getItemPaint(int row, int col) {
if(!offline){
return super.getItemPaint(row, col);
}else{
return new Color(0, 0, 0);
}
}
}
private void start() {
timer.start();
}
public static void main(final String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Test demo = null; //pass date in from csv
try {
demo = new Test(TITLE);
} catch (ParseException e) {
e.printStackTrace();
}
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
demo.start();
}
});
}
}
What am I doing wrong?
One approach would be to append an appropriate baseline value when off line. Starting from this example, the range is centered on a value of zero millivolts. The modification below adds zeroes between 60 and 90 milliseconds:
private float[] gaussianData() {
float[] a = new float[COUNT];
for (int i = 0; i < a.length; i++) {
if (i > 60 && i < 90) a[i] = 0;
else a[i] = randomValue();
}
return a;
}
In my instance, a period of offline should effectively stop graphing.
Use the approach suggested here, which uses setMaximumItemAge() to limit the number of displayed records. Add null values, as suggested here, to interrupt the display. Starting from this example, I got this display with these changes:
seriesA.setMaximumItemCount(120);
seriesB.setMaximumItemCount(120);
…
int i;
…
public void addNull() {
this.seriesA.add(new Millisecond(), null);
this.seriesB.add(new Millisecond(), null);
}
#Override
public void actionPerformed(ActionEvent e) {
if (i > 60 && i < 90) {
demo.addNull();
} else {
…
}
i++;
}

What if I want to display only the values I want to display on the X axis in the Android line chart whith mpAndroidchart

It is the current state of my project
I want to change this
this is my code
Blockquote
public class MainActivity extends AppCompatActivity {
LineChart mChart;
private static final float MAX_BP_VALUE = 220f;
private static final float MAX_BT_VALUE = 42f;
private static final float UPPER_LIMIT = 130.0f;
private static final float LOWER_LIMIT = 50.0f;
private static SimpleDateFormat mFormat = new SimpleDateFormat("yyyy:mm:dd");
IAxisValueFormatter xAxisFormatter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mFormat.setTimeZone(TimeZone.getDefault());
mChart = (LineChart) findViewById(R.id.chart);
xAxisFormatter = new IAxisValueFormatter() {
public int getDecimalDigits() {
return 0;
}
#Override
public String getFormattedValue(float value, AxisBase axis) {
return mFormat.format(new Date((long) value));
}
};
setupChart();
setupAxes();
setupData();
setLegend();
Button drawButton = (Button) findViewById(R.id.drawButton);
drawButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
LineData data = mChart.getData();
LineDataSet dataset = BPcreateSet();
try {
dataset.addEntry(new Entry(new Long(mFormat.parse("2018:05:11").getTime()).floatValue(), 110));
dataset.addEntry(new Entry(new Long(mFormat.parse("2018:06:13").getTime()).floatValue(), 150));
dataset.addEntry(new Entry(new Long(mFormat.parse("2018:07:15").getTime()).floatValue(), 120));
dataset.addEntry(new Entry(new Long(mFormat.parse("2018:08:17").getTime()).floatValue(), 80));
dataset.addEntry(new Entry(new Long(mFormat.parse("2018:09:18").getTime()).floatValue(), 40));
} catch(Exception e) {
e.printStackTrace();
}
ArrayList<Integer> colorList = new ArrayList<Integer>();
colorList.add(Color.WHITE);
colorList.add(Color.RED);
colorList.add(Color.WHITE);
colorList.add(Color.WHITE);
colorList.add(Color.BLUE);
dataset.setCircleColors(colorList);
data.addDataSet(dataset);
mChart.setData(data);
data.notifyDataChanged();
mChart.notifyDataSetChanged();
mChart.animateX(1000);
}
});
}
private void setupChart() {
mChart.getDescription().setEnabled(false);
mChart.setTouchEnabled(true);
mChart.setPinchZoom(true);
mChart.setScaleEnabled(true);
mChart.setDrawGridBackground(false);
mChart.setBackgroundColor(Color.BLACK);
mChart.setMarker(new XYMarkerView(this, xAxisFormatter));
mChart.setDrawMarkers(true);
}
private void setupAxes() {
XAxis xl = mChart.getXAxis();
xl.setPosition(XAxis.XAxisPosition.BOTTOM);
xl.setTextColor(Color.WHITE);
xl.setDrawGridLines(false);
xl.setAvoidFirstLastClipping(true);
xl.setEnabled(true);
xl.setLabelRotationAngle(-45.0f);
xl.setGranularityEnabled(true);
xl.setGranularity(1.0f/6.0f); // per 10 minutes
xl.setDrawGridLines(true);
xl.setAxisLineWidth(2f);
xl.setAxisLineColor(Color.WHITE);
xl.setValueFormatter(xAxisFormatter);
YAxis leftAxis = mChart.getAxisLeft();
leftAxis.setTextColor(Color.WHITE);
leftAxis.setAxisMaximum(MAX_BP_VALUE);
leftAxis.setAxisMinimum(20f);
leftAxis.setGranularity(20f);
leftAxis.setAxisLineWidth(2f);
leftAxis.setAxisLineColor(Color.WHITE);
leftAxis.setLabelCount(10);
leftAxis.setDrawGridLines(true);
YAxis rightAxis = mChart.getAxisRight();
rightAxis.setTextColor(Color.WHITE);
rightAxis.setAxisMaximum(MAX_BT_VALUE);
rightAxis.setAxisMinimum(32f);
rightAxis.setGranularity(2f);
rightAxis.setAxisLineWidth(2f);
rightAxis.setAxisLineColor(Color.WHITE);
rightAxis.setDrawGridLines(false);
xl.setSpaceMin(50);
LimitLine ul = new LimitLine(UPPER_LIMIT, "Upper Limit");
ul.setLineWidth(2f);
ul.setLabelPosition(LimitLine.LimitLabelPosition.RIGHT_TOP);
ul.setTextSize(10f);
ul.setTextColor(Color.WHITE);
LimitLine ll = new LimitLine(LOWER_LIMIT, "Lower Limit");
ll.setLineColor(Color.BLUE);
ll.setLineWidth(2f);
ll.setLabelPosition(LimitLine.LimitLabelPosition.LEFT_TOP);
ll.setTextSize(10f);
ll.setTextColor(Color.WHITE);
LimitLine llI = new LimitLine(400f, "체온");
llI.setLineColor(Color.BLUE);
llI.setLineWidth(2f);
llI.setLabelPosition(LimitLine.LimitLabelPosition.RIGHT_BOTTOM);
leftAxis.removeAllLimitLines();
leftAxis.addLimitLine(ul);
leftAxis.addLimitLine(ll);
xl.addLimitLine(llI);
leftAxis.setDrawLimitLinesBehindData(true);
}
private void setupData() {
LineData data = new LineData();
data.setValueTextColor(Color.WHITE);
// add empty data
mChart.setData(data);
}
private void setLegend() {
Legend l = mChart.getLegend();
l.setForm(Legend.LegendForm.CIRCLE);
l.setTextColor(Color.WHITE);
}
private LineDataSet BPcreateSet() {
LineDataSet set = new LineDataSet(null, "pulse");
set.setAxisDependency(YAxis.AxisDependency.LEFT);
set.setColors(Color.argb(255, 0, 255, 0));
set.setLineWidth(3f);
set.setCircleRadius(6f);
set.setValueTextColor(Color.WHITE);
set.setValueTextSize(10f);
set.setDrawValues(false);
return set;
}
}
I want to mark the X-axis like the picture above.
Please excuse me that First and last values is empty because I am poor at Photoshop.
Is there a solution?
You can also recommend another library that represents the time value and indicates the value required for the X-axis

How to edit tables in javafx? [duplicate]

This question already has an answer here:
Javafx TableView not showing data
(1 answer)
Closed 4 years ago.
Purpose: To browse for a folder and select it. And to add its properties in columns.
For example, the name of the folder goes in the name column, the location goes in the location, and etc.
For some reason, I am not able to add the properties of selected folder into the table named folderTable. The program seem to know that something is in the first row after I add a folder but it doesn't display the folder itself.
I am learning, so any help is appreciated.
public class mainClass2 extends Application {
Stage window;
TableView<syncedFolders> folderTable;
Button file, edit, view, addFolder, printInfo, close, deleteFolder;
private String name, location, dateModified;
private long size;
private double printSize = 0, bytes = 0, kilobytes = 0, megabytes = 0, gigabytes = 0, tempSize = 0;
private String printSizeAb = "";
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
window = primaryStage;
HBox topMenu = new HBox();
file = new Button("File");
edit = new Button("Edit");
view = new Button("View");
topMenu.getChildren().addAll(file, edit, view);
VBox leftMenu = new VBox();
printInfo = new Button("Print folder info");
printInfo.setOnAction(e -> {
round(printSize, 1);
System.out.println("Name: " + name);
System.out.println("Location: " + location);
System.out.println("Last Modified: " + dateModified);
System.out.println("Size: " + tempSize + printSizeAb);
});
leftMenu.getChildren().add(printInfo);
HBox botBox = new HBox();
addFolder = new Button("Add Folder");
deleteFolder = new Button("Delete Folder");
close = new Button("Exit");
addFolder.setOnAction(e -> {
DirectoryChooser chooser = new DirectoryChooser();
chooser.setTitle("JavaFX Projects");
File defaultDirectory = new File("D:\\");
chooser.setInitialDirectory(defaultDirectory);
File selectedDirectory = chooser.showDialog(window);
name = selectedDirectory.getName();
location = selectedDirectory.toString();
size = getFolderSize(selectedDirectory);
bytes = size;
kilobytes = (bytes / 1024);
megabytes = (kilobytes / 1024);
gigabytes = (megabytes / 1024);
if (bytes < 1024) {
printSize = kilobytes;
printSizeAb = " KB";
} else if (bytes >= 1024 && bytes < Math.pow(1024, 3)) {
printSize = megabytes;
printSizeAb = " MB";
} else // if (bytes >= Math.pow(1024, 2) && bytes <= Math.pow(1024, 3))
{
printSize = gigabytes;
printSizeAb = " GB";
}
addFolder();
lasModifiedDate();
});
// Name column
TableColumn<syncedFolders, String> nameCol = new TableColumn<>("Name");
nameCol.setMinWidth(200);
nameCol.setCellValueFactory(new PropertyValueFactory<>("name"));
// location column
TableColumn<syncedFolders, String> locationCol = new TableColumn<>("Location");
locationCol.setMinWidth(200);
locationCol.setCellValueFactory(new PropertyValueFactory<>("location"));
// date modified column
TableColumn<syncedFolders, String> dateModifiedCol = new TableColumn<>("Last Modified");
dateModifiedCol.setMinWidth(200);
dateModifiedCol.setCellValueFactory(new PropertyValueFactory<>("dateModified"));
// size column
TableColumn<syncedFolders, Double> sizeCol = new TableColumn<>("Size");
sizeCol.setMinWidth(200);
sizeCol.setCellValueFactory(new PropertyValueFactory<>("size"));
folderTable = new TableView<>();
folderTable.setItems(getSyncedFolders());
folderTable.getColumns().addAll(nameCol, locationCol, dateModifiedCol, sizeCol);
close.setOnAction(e -> closeProgram());
botBox.setPadding(new Insets(10, 10, 10, 10));
botBox.setSpacing(10);
botBox.getChildren().addAll(addFolder, deleteFolder, close);
BorderPane borderPane = new BorderPane();
borderPane.setTop(topMenu);
borderPane.setLeft(leftMenu);
borderPane.setCenter(folderTable);
borderPane.setBottom(botBox);
Scene scene = new Scene(borderPane, 800, 600);
window.setScene(scene);
window.setTitle("the title");
window.show();
window.setOnCloseRequest(e -> {
e.consume();
closeProgram();
});
}
// Get all of the products
public ObservableList<syncedFolders> getSyncedFolders() {
ObservableList<syncedFolders> folders = FXCollections.observableArrayList();
folders.add(new syncedFolders("Folder", "D://", "July", 3.4));
folders.add(new syncedFolders(name, location, dateModified, tempSize));
return folders;
}
public void addFolder() {
round(printSize, 1);
folderTable.setItems(getSyncedFolders());
folderTable.getItems().add(new syncedFolders(name, location, dateModified, tempSize));
}
private double round(double value, int precision) {
int scale = (int) Math.pow(10, precision);
tempSize = (double) Math.round(value * scale) / scale;
return tempSize;
}
public String lasModifiedDate() {
Path path = Paths.get(location);
DateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy - hh:mm:ss");
FileTime fileTime = null;
try {
fileTime = Files.getLastModifiedTime(path);
} catch (IOException e1) {
System.out.println("Cannot get the last modified time");
}
dateModified = dateFormat.format(fileTime.toMillis());
return dateModified;
}
private long getFolderSize(File folder) {
long length = 0;
File[] files = folder.listFiles();
int count = files.length;
for (int i = 0; i < count; i++) {
if (files[i].isFile()) {
length += files[i].length();
} else {
length += getFolderSize(files[i]);
}
}
return length;
}
private void closeProgram() {
/**
* Alert alert = new Alert(AlertType.CONFIRMATION); alert.setTitle("Confirmation
* Dialog"); alert.setHeaderText("You are about to exit");
* alert.setContentText("Are you ok with this?");
*
* Optional<ButtonType> result = alert.showAndWait(); if (result.get() ==
* ButtonType.OK)
**/
window.close();
}
}
public class syncedFolders {
private String name, location, dateModified;
private double size;
public syncedFolders() {
this.name = "";
this.location = "";
this.dateModified = "";
this.size = 0;
}
public syncedFolders(String s) {
this.name = s;
}
public syncedFolders(String name, String location, String dateModified, double size) {
this.name = name;
this.location = location;
this.dateModified = dateModified;
this.size = size;
}
public String getname() {
return name;
}
public void setname(String s) {
name = s;
}
public String getlocation() {
return location;
}
public void setlocation(String s) {
location = s;
}
public String getdateModified() {
return dateModified;
}
public void setdateModified(String s) {
dateModified = s;
}
public double getsize() {
return size;
}
public void setsize(double d) {
size = d;
}
}
The TableView uses Properties and Bindings to display the data in each column. You have a CellValueFactory installed on the columns, but you're populating it usinga PropertyValueFactory.
That is the right way to do it, but there's a problem with your syncedFolders class. The PropertyValueFactory looks into your syncedFolders class and tries to find a Property with the name you specified. The problem is that you do not have any properties defined:
private String name, location, dateModified;
private double size;
These are fields, not properties.
You will need to rewrite your syncedFolders class to have observable properties instead, like this:
private SimpleStringProperty name = new SimpleStringProperty();
Do that for each of your fields, update your constructor and setters/getters and try again!
public class syncedFolders {
private SimpleStringProperty name = new SimpleStringProperty();
private SimpleStringProperty location = new SimpleStringProperty();
private SimpleStringProperty dateModified = new SimpleStringProperty();
private SimpleDoubleProperty size = new SimpleDoubleProperty();
public syncedFolders(
String name,
String location,
String dateModified,
double size) {
this.name.set(name);
this.location.set(location);
this.dateModified.set(dateModified);
this.size.setValue(size);
}
public String getName() {
return name.get();
}
public SimpleStringProperty nameProperty() {
return name;
}
public void setName(String name) {
this.name.set(name);
}
public String getLocation() {
return location.get();
}
public SimpleStringProperty locationProperty() {
return location;
}
public void setLocation(String location) {
this.location.set(location);
}
public String getDateModified() {
return dateModified.get();
}
public SimpleStringProperty dateModifiedProperty() {
return dateModified;
}
public void setDateModified(String dateModified) {
this.dateModified.set(dateModified);
}
public double getSize() {
return size.get();
}
public SimpleDoubleProperty sizeProperty() {
return size;
}
public void setSize(double size) {
this.size.set(size);
}
}
EDIT:
I would also recommend changing how you populate your table. Your current addFolder() method is adding the item directly to the table's items property, but you really should add them to the underlying ObservableList that is set as the table's items:
public void addFolder() {
round(printSize, 1);
folderTable.setItems(getSyncedFolders());
folderTable.getItems().add(new syncedFolders(name, location, dateModified, tempSize));
}
The way folderTable.setItems() works is that it binds a list to the TableView. But that I mean that any changes made to the list will be reflected in the TableView automatically; you should not need to use folderTable.getItems().add() at all.

Update JFreeChart from thread

I have to build a GPS parser. I need to parse the NMEA string in another thread, which will be parsing a single NMEA string and update chart at 1 Hz. For now I build part of my code, but I parse data in main thread in while loop; my teacher said that is wrong. I was programming some on Java but not in multi-threading aspects. How I could move parsing process and refreshing chart to background thread?
public class MainFrame extends JFrame {
private JButton btnWybPlik;
private JLabel jlDroga;
private JLabel jlPredkosc;
private JLabel jlCzas;
private JPanel mainjpanel;
private JPanel jpMenu;
private JPanel jpTablica;
//private String sciezkaPliku;
private SekwencjaGGA sekGGA = null;
private SekwencjaGGA popSekGGA = null;
private SekwencjaGSA sekGSA;
private SekwencjaGLL sekGLL;
private SekwencjaRMC sekRMC;
private double droga;
private double predkosc;
private XYSeries series1;
private XYSeriesCollection dataset;
public MainFrame() {
droga = 0;
btnWybPlik.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setCurrentDirectory(new File(System.getProperty("user.home")));
int result = fileChooser.showOpenDialog(mainjpanel);
if (result == JFileChooser.APPROVE_OPTION) {
File selectedFile = fileChooser.getSelectedFile();
//System.out.println("Selected file: " + selectedFile.getAbsolutePath());
String sciezkaPliku = selectedFile.getAbsolutePath();
wczytaniePliku(sciezkaPliku);
}
}
});
jpTablica = new JPanel();
mainjpanel.add(jpTablica);
this.series1 = new XYSeries("Trasa", false);
final XYSeriesCollection dataset = new XYSeriesCollection(this.series1);
final JFreeChart chart = createChart(dataset);
final ChartPanel chartPanel = new ChartPanel(chart);
jpTablica.add(chartPanel);
}
private void wczytaniePliku(String sciezkaDoPliku) {
try (BufferedReader br = new BufferedReader(new FileReader(sciezkaDoPliku))) {
String line;
//series1.add(53.448, 14.4907);
while ((line = br.readLine()) != null) {
parseLine(line);
}
//series1.add(53.4485, 14.4910);
} catch (IOException e) {
e.printStackTrace();
}
}
private void parseLine(String line) {
String bezSumKont = line.substring(0, line.length() - 3);
List<String> podzSekw = Arrays.asList(bezSumKont.split(","));
if (podzSekw.get(0).equalsIgnoreCase("$GPGGA")) {
if (check(line)) {
if (sekGGA != null)
popSekGGA = sekGGA;
sekGGA = new SekwencjaGGA(podzSekw);
if (popSekGGA != null) {
droga += obliczOdleglosc(popSekGGA, sekGGA);
jlDroga.setText(String.valueOf(droga));
}
series1.add(sekGGA.getWspolzedne().getLongitude(), sekGGA.getWspolzedne().getLatitude());
System.out.println(sekGGA.getWspolzedne().getLatitude() + " " + sekGGA.getWspolzedne().getLongitude());
//System.out.println(series1.getMaxY() + " " + series1.getMinY());
} else {
//TODO: Zlicz błąd
}
}
if (podzSekw.get(0).equalsIgnoreCase("$GPGSA")) {
if (check(line)) {
sekGSA = new SekwencjaGSA(podzSekw);
} else {
//TODO: Zlicz błąd
}
}
if (podzSekw.get(0).equalsIgnoreCase("$GPGLL")) {
if (check(line)) {
sekGLL = new SekwencjaGLL(podzSekw);
} else {
//TODO: Zlicz błąd
}
}
if (podzSekw.get(0).equalsIgnoreCase("$GPRMC")) {
//TODO: Sekwencja RMC (Recommended minimum of data)
if (check(line)) {
sekRMC = new SekwencjaRMC(podzSekw);
} else {
//TODO: Zlicz błąd
}
}
}
private double obliczOdleglosc(SekwencjaGGA pkt1, SekwencjaGGA pkt2) {
double odleglosc = 0;
double earthRadius = 6371000; //meters
double dLat = Math.toRadians(pkt2.getWspolzedne().getLatitude() - pkt1.getWspolzedne().getLatitude());
double dLng = Math.toRadians(pkt2.getWspolzedne().getLongitude() - pkt1.getWspolzedne().getLongitude());
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(Math.toRadians(pkt1.getWspolzedne().getLatitude())) * Math.cos(Math.toRadians(pkt1.getWspolzedne().getLatitude())) *
Math.sin(dLng / 2) * Math.sin(dLng / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
odleglosc = earthRadius * c;
return odleglosc;
}
/**
* Funkcja sprawdzająca sume kontrolną
*
* #param tekst cała linia NMEA
* #return true jeśli się suma kontrolna zgadza
*/
private boolean check(String tekst) {
String suma = tekst.substring(tekst.length() - 2, tekst.length());
tekst = tekst.substring(1, tekst.length() - 3);
int checksum = 0;
for (int i = 0; i < tekst.length(); i++) {
checksum = checksum ^ tekst.charAt(i);
}
if (Integer.parseInt(suma, 16) == checksum) {
return true;
}
return false;
}
private JFreeChart createChart(final XYDataset dataset) { ... }
private void customizeChart(JFreeChart chart) { ... }
public static void main(String[] args) {
JFrame frame = new JFrame("MainFrame");
frame.setContentPane(new MainFrame().mainjpanel);
frame.setPreferredSize(new Dimension(640, 480));
frame.pack();
frame.setVisible(true);
}
To avoid blocking the event dispatch thread, construct an instance of SwingWorker. Collect data in your implementation of doInBackground(), publish() intermediate results, and update the XYSeries in your implementation of process(). The listening chart will update itself in response. A related example that uses jfreechart is seen below and examined here.

Categories