Ich mache eine GUI, die das Ergebnis von Hintergrundberechnungen anzeigt. Aber vorher wollte ich das Ändern des Datensatzes testen. Hier ist mein Code:
DefaultXYDataset dataset = new DefaultXYDataset();
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < periods; i++) {
series[0][i] = (double) i;
series[1][i] = 0;
}
dataset.addSeries("Series0", series);
for (int it = 0; it < 10; it++) {
series[1][random.nextInt(periods)] = random.nextInt(100) / 2;
double[][] d = new double[2][periods];
for (int i = 0; i < periods; i++) {
d[0][i] = series[0][i];
d[1][i] = series[1][i];
}
dataset.removeSeries("Series0");
dataset.addSeries("Series0", series);
// try {
// Thread.sleep(100);
// } catch (java.lang.InterruptedException ex) {
// }
}
Wie Sie sehen können, möchte ich Punkte im Diagramm ändern (jedes Mal, wenn es “einige komplizierte Berechnungen” beendet) – diese Änderung befindet sich in dem von mir in einer anderen Klasse aufgerufenen Thread. Mein Problem ist, dass dieses ganze Konzept nicht funktioniert. Es wirft ‘Serienindex außerhalb der Grenzen’ – IllegalArgumentException, ‘Index außerhalb der Grenzen’ – einer inneren Arrayliste einer Bibliothek usw. Ich verwende DynamicTimeSeriesCollection nicht, da die X-Achse die Anzahl meiner inneren Iterationen und nicht die Zeit sein muss Zeitraum, und aktualisieren Sie auch, wenn “einige Berechnungen” abgeschlossen sind, nicht in jedem Zeitraum. Können Sie mir sagen, was ich falsch mache? Oder gibt es eine bessere Möglichkeit, das Diagramm zu aktualisieren/aktualisieren?
Ihr Snippet ist falsch synchronisiert; du solltest deine aktualisieren dataset
von dem process()
Methode von a SwingWorker
, wie hier gezeigt. Da Ihre Domäne “die Anzahl meiner inneren Iterationen” ist, verwenden Sie kein a DateAxis
; Verwenden Sie stattdessen a NumberAxis
wie gezeigt in ChartFactory.createXYLineChart()
.
Nachtrag: Diese Variation des Beispiels zeigt den Fortschritt des Arbeiters in einem Liniendiagramm. Beachten Sie, dass createXYLineChart()
Verwendet NumberAxis
sowohl für die Domäne als auch für den Bereich. Angenommen series
Beachten Sie im Datensatz des Liniendiagramms auch, wie die Implementierung von process()
kann den Datensatz sicher aktualisieren, wenn neue Daten eintreffen; Das Listening-Diagramm wird sich als Reaktion darauf aktualisieren.
private XYSeries series = new XYSeries("Result");
…
@Override
protected void process(List<Double> chunks) {
for (double d : chunks) {
label.setText(df.format(d));
series.add(++n, d);
}
}

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.beans.PropertyChangeEvent;
import java.text.DecimalFormat;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
/**
* @see https://stackoverflow.com/a/13205322/230513
* @see https://stackoverflow.com/questions/4637215
*/
public final class ChartWorker {
private static final String S = "0.000000000000000";
private final JProgressBar progressBar = new JProgressBar();
private final JLabel label = new JLabel(S, JLabel.CENTER);
private final XYSeries series = new XYSeries("Result");
private final XYDataset dataset = new XYSeriesCollection(series);
private void create() {
JFrame f = new JFrame("√2");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(progressBar, BorderLayout.NORTH);
JFreeChart chart = ChartFactory.createXYLineChart(
"Newton's Method", "X", "Y", dataset,
PlotOrientation.VERTICAL, false, true, false);
XYPlot plot = (XYPlot) chart.getPlot();
plot.getRangeAxis().setRange(1.4, 1.51);
plot.getDomainAxis().setStandardTickUnits(
NumberAxis.createIntegerTickUnits());
XYLineAndShapeRenderer renderer
= (XYLineAndShapeRenderer) plot.getRenderer();
renderer.setSeriesShapesVisible(0, true);
f.add(new ChartPanel(chart) {
@Override
public Dimension getPreferredSize() {
return new Dimension(640, 480);
}
}, BorderLayout.CENTER);
f.add(label, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
runCalc();
}
private void runCalc() {
progressBar.setIndeterminate(true);
TwoWorker task = new TwoWorker();
task.addPropertyChangeListener((PropertyChangeEvent e) -> {
if ("progress".equals(e.getPropertyName())) {
progressBar.setIndeterminate(false);
progressBar.setValue((Integer) e.getNewValue());
}
});
task.execute();
}
private class TwoWorker extends SwingWorker<Double, Double> {
private static final int N = 5;
private final DecimalFormat df = new DecimalFormat(S);
double x = 1;
private int n;
@Override
protected Double doInBackground() throws Exception {
for (int i = 1; i <= N; i++) {
x = x - (((x * x - 2) / (2 * x)));
setProgress(i * (100 / N));
publish(x);
Thread.sleep(1000); // simulate latency
}
return x;
}
@Override
protected void process(List<Double> chunks) {
for (double d : chunks) {
label.setText(df.format(d));
series.add(++n, d);
}
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new ChartWorker()::create);
}
}
Sie müssen den entsprechenden Code hier mit Ihrer Frage posten. Am besten wäre so nah an einem scce wie du bekommen könntest.
– Hovercraft voller Aale
3. November 2012 um 2:00 Uhr
Ich bin mir nicht sicher, ob dies etwas ändert, da das Problem imo mit dem von mir bereitgestellten Code zusammenhängt. Aber solange Sie bereit sind, mir zu helfen, ist dies der vollständige Code:pastebin.com/zEBHZYj4 . Diese Klasse wird zu einigen JPanel hinzugefügt, ich rufe new Thread(JPaintablePanel).start(); mit einem Knopf
– aragornsql
3. November 2012 um 2:15 Uhr