Search code examples
javaswinguser-interfacejfreechart

JFreeChart Plot Dynamically when JTable changes


I have a JTable that displays my data. This two JTable contain two Column (col1 for Time and col2 for values of a CO2 sensor). With a click on Start button, the data will added to the table with a period that I may enter through the console,

After each change in the table of the Koordianten x = time, y = CO2 values, a line chart dynamic it must be shown.

How can I display this Linechart Dynamically. This is my Code:

public PanelGraphic() throws NotConnectedException {
    initComponents();
}

private static JFreeChart createChart(final XYDataset dataset) {
    JFreeChart chart = ChartFactory.createXYLineChart(
        "KohlendioxdeTest", "Time ", "CO2 (ppm)", dataset,
        PlotOrientation.VERTICAL, false, false, false);
    return chart;
}

private void display(){    
    JFreeChart chart = createChart(dataset);
    ChartPanel panel = new ChartPanel(chart);
    final XYPlot plot = (XYPlot) chart.getPlot();
    panel.setPreferredSize(new java.awt.Dimension(515, 265));
    PlGraph.setLayout(new java.awt.BorderLayout());
    PlGraph.add(panel, BorderLayout.CENTER);
    PlGraph.validate();    
}

private void jButtonStartActionPerformed(java.awt.event.ActionEvent evt) {



final DefaultTableModel model = (DefaultTableModel) tbCO2Value.getModel();

try {
if (!txtSetPeriode.getText().trim().isEmpty()) {

double peri = Long.parseLong(txtSetPeriode.getText());
co2.setCO2CallbackPeriod((long) peri * 1000);
co2.addCO2PPMListener(new BrickletCO2.PPmListener() {

@Override
public void PPmconverter(int kohlendioxide) {
model.addRow(new Object[]{DisplayTime.getTime(), String.valueOf(kohlendioxide)});
}
});
} else {
lbComment.setText("Bitte geben sie die Periode ein");
}


} catch (NotConnectedException ex) {
Logger.getLogger(PanelGraphic.class.getName()).log(Level.SEVERE, null, ex);
} catch (TimeoutException ex) {
Logger.getLogger(PanelGraphic.class.getName()).log(Level.SEVERE, null, ex);
}

tbCO2Value.getModel().addTableModelListener(new MyTableModelListener(tbCO2Value));
dataset = new XYSeriesCollection();


XYSeries series = new XYSeries("CO2 (ppm)");
int nRow = tbCO2Value.getRowCount();
int nCol = tbCO2Value.getColumnCount();
Object[][] tableData = new Object[nRow][nCol];
for (int i = 0; i < nRow; i++) {

tableData[i][0] = tbCO2Value.getValueAt(i, 0);
tableData[i][1] = tbCO2Value.getValueAt(i, 1);
// for (int i = 0; i < 10; i++) {
series.add((double) tableData[i][0],(double) tableData[i][1] );
}
dataset.addSeries(series);

display();

}
class MyTableModelListener implements TableModelListener {

JTable table;

private MyTableModelListener(JTable table) {
this.table = table;
}

@Override
public void tableChanged(TableModelEvent e) {

int firstRow = e.getFirstRow();
int lastRow = e.getLastRow();
int index = e.getColumn();

switch (e.getType()) {
case TableModelEvent.INSERT:
int nRow = tbCO2Value.getRowCount();
int nCol = tbCO2Value.getColumnCount();
Object[][] tableData = new Object[nRow][nCol];
for (int i = 0; i < nRow; i++) {

tableData[i][0] = tbCO2Value.getValueAt(i, 0);
tableData[i][1] = tbCO2Value.getValueAt(i, 1);


}
break;

}
}
}
}

Solution

  • Just as a JTable listens to its TableModel, an XYPlot listens to its own XYDataset. In each case, simply update the relevant model and the corresponding view will update itself in response. Use a javax.swing.Timer to poll your data source at the rate prescribed by the chosen period. A related example is shown here. In outline, your timer's ActionListener might look like this:

    @Override
    public void actionPerformed(ActionEvent e) {
        // poll the data source
        model.add(Row(…);
        dataset.add(…);
    }
    

    If you anticipate latency in accessing the data source, consider using a SwingWorker, illustrated here and here.