# JFreeChart Skalierung zur Laufzeit ändern



## RainerUnsinn (28. Feb 2011)

Hallo Forengemeinde,

ich bin gerade dabei mit JFreeChart ein TimeSeries Diagramm zu erstellen, welches momentan noch Zufallszahlen und später Sensorwerte in Abhängigkeit der Zeit darstellen soll. Das funktioniert bisher auch ganz gut. Allerdings würde ich gerne während sich das Diagramm dynamisch aktualisiert über eine JCombobox die Skalierung der Zeitachse ändern. Ich habe aber keine Idee wie ich das umsetzen soll. Über die axis.setFixedAutoRange() müste ja die Skalierung geholt werden, was aber nur zu Beginn beim erstellen des Diagramms geschieht. Wie kann ich also zur Laufzeit die axis.setFixedAutoRange() aktualisieren? Wäre schön wenn jemand einen Hinweis hat. Vielen Dank.


----------



## RainerUnsinn (1. Mrz 2011)

Hat wirklich niemand eine Idee wie das zu realisieren geht?


----------



## Harry Kane (2. Mrz 2011)

Hallo Rainer,
vielleicht habe ich da was nicht verstanden. Was hindert dich daran, setFixedAutoRange(double length) zu einem von dir gewählten Zeitpunkt aufzurufen?
Das double Argument kannst du dir aus einer JComboBox, einem JTextField oder aus einem JSpinner holen. Du müsstest an diese Komponenten nur einen geeigneten Listener hängen, der auch eine Referenz zu der domain axis hat, und wenn die Komponente einen event losschickt, weil der Benutzer damit rumgespielt hat, setFixedAutoRange(double) auf der domain aixis aufrufen.


----------



## RainerUnsinn (2. Mrz 2011)

Hallo Harry,

erst einmal vielen Dank für deine Antwort. Das double Argument hole ich auch aus einer JComboBox. Nur wie rufe ich die setFixedAutoRange(double) auf? Ich habe das ganze über ein MVC Pattern gelöst. Die JComboBox wird auch vom Controller ausgelesen. Dann schicke ich den Wert zur View zurück. Nur dann weiß ich nicht wie es weiter gehen soll. Wäre dir für einen Hinweis sehr dankbar. Der Code dazu. Hier wird das Diagramm erstellt:

```
public JFreeChart createChart(final XYDataset dataset) {
        final JFreeChart result = ChartFactory.createTimeSeriesChart(
            null, 			//Titel Diagramm
            null, 			//Beschriftung x-Achse
            "m³/h",			//Beschriftung y-Achse
            dataset, 		//verwendeter Datensatz
            false, 			//Legende anzeigen
            true, 			//Tooltips
            false);			//URLs
        XYPlot plot = result.getXYPlot();
        ValueAxis axis = plot.getDomainAxis();
        axis.setAutoRange(true);			//Autoskalierung der y-Achse
        axis.setFixedAutoRange(60000);	//Skalierung x-Achse 
        axis = plot.getRangeAxis();
        return result;
    }
```

Und hier wird das Ergebnis der JComboBox ausgewertet:

```
public void setRange(double range){
    	this.r = range;
        //hier müsste die setFixedAutoRange aufgerufen werden???
    }
```


----------



## Harry Kane (3. Mrz 2011)

Also wenn du in einer Methode ein Objekt manipulieren möchtest, welches du in einer anderen Methode erzeugt hast, musst du dieses Objekt "methodenübergreifend" zur Verfügung stellen, also als Instanz- oder Klassenvariable, oder zumindest einen methodenübergreifende Weg, auf das Objekt zuzugreifen.

Wenn sich die createChart() und die setRange() methode in derselben Klasse befinden, müsstest du den JFreeChart, den XYPlot oder direkt die ValueAxis als Instanzvariable deklarieren.

ich würde mir eine Klasse schreiben, die das ActionListener interface implementiert, und einer INstanz der Klasse eine Referenz auf die ValueAxis übergeben. Dann wird die ActionListener-Instanz als ActionListener bei der JComboBox registriert.
Dann musst du nur noch in der actionPerformed(ActionEvent) methode des listeners die source des ActionEvents (welches die JComboBox ist) zu einer JComboBox casten, den Wert mit JComboBox.getSelectedItem() beschaffen, daraus irgendwie eine Zahl machen und die als Argument an SetFixedAutoRange-Methode der ValueAxis, auf die die listenmer-Klasse ja zugreifen kann, übergeben.


----------



## RainerUnsinn (4. Mrz 2011)

Tut mir leid. Ich stehe gerade irgendwie auf dem Schlauch. Also die createChart() und die setRange befinden sich in der selben Klasse. In einer weiteren Klasse wird die JComboBox implementiert. Hab das allerdings mit dem ItemListener gelöst.

```
class ComboRangeListener implements ItemListener{			
		public void itemStateChanged(ItemEvent e){
			JComboBox selectedChoice = (JComboBox) e.getSource();
			if("20 min".equals(selectedChoice.getSelectedItem())){
				_view.setRange(1200000);
			}
			else if("60 min".equals(selectedChoice.getSelectedItem())){
				_view.setRange(3600000);
			}
		}
}
```
Nur mir ist immer noch nicht ganz klar wo genau die setFixedAutoRange ins Spiel kommt:bahnhof: Bin noch nicht so erfahren in Java. Vielen Dank für deine Geduld mit mir


----------



## Harry Kane (4. Mrz 2011)

Offenbarf hast du eine Sammlung von Klassen, die irgendwie zusammenarbeiten müssen. Im Kern musst du zu der Lösung deines Problems nur dafür sorgen, daß ein objekt sowohl als Listener auf der JComboBox registriert wird, als auch Zugriff auf die ValueAxis bekommen kann, um den Wertebereich zu setzen.
Hier mal ein rudimentäres Beispiel:

```
public class SimpleXYPlot{
	public static void main(String[] args){
		DefaultXYDataset dataset = new DefaultXYDataset();
		dataset.addSeries("Red Circles And Lines",new double[][]{{1, 2, 3}, {2, 4, 1}});		
		ValueAxis xAxis = new NumberAxis("x axis");
		ValueAxis yAxis = new NumberAxis("y axis");
		XYItemRenderer renderer = new XYLineAndShapeRenderer();
		XYPlot plot = new XYPlot(dataset, xAxis, yAxis, renderer);
		JFreeChart chart = new JFreeChart(plot);
		JFrame frame = new JFrame();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.getContentPane().add(new ChartPanel(chart));
		JComboBox box = new JComboBox(new Integer[]{1,10,20});
		box.addActionListener(new AxisRangeController(xAxis));
        frame.getContentPane().add(box, BorderLayout.NORTH);
        frame.pack();
        frame.setVisible(true);
        
	}
    static class AxisRangeController implements ActionListener{
        private ValueAxis va;
        AxisRangeController(ValueAxis va){
            this.va = va;
        }   
        public void actionPerformed(ActionEvent ae){
            Object source = ae.getSource();
            if(!(source instanceof JComboBox)) return;
            Object value = ((JComboBox)source).getSelectedItem();
            if(!(value instanceof Number)) return;
            va.setFixedAutoRange(((Number)value).doubleValue());
        }
    }
}
```
Wie du dies am besten in deine schon vorhandenen Klassen integrierst, ist kaum zu sagen.
Was ist eigentlich das "_view" Object, auf das dein ComboRangeListener zugreift? Kannst du diesem object eine Referenz auf die ValueAxis übergeben?


----------



## RainerUnsinn (6. Mrz 2011)

Vielen Dank Harry. Es funktioniert genauso wie ich mir das vorgestellt habe:toll: Der entscheidene Punkt war wie du gesagt hast die Anmeldung der ValueAxis am Listener.


----------

