# ActionListener und repaint()



## andyle (10. Nov 2007)

Hallo zusammen,

nach intensiver Recherche bin ich zu keiner Lösung gekommen und hoffe von euch auf Hilfe.

Bei dem Projekt (Visualisierung von Hashing) arbeite ich mit Eclipse und Swing.
Ich habe eine Datenstruktur (List) die bei manuellen Änderungen (setValue) einen Observer (JPanel) informiert (notify), welcher dann die Daten neu zeichnet (Java2D, repaint -> paint). Funktioniert soweit.
Nun möchte ich in einer Schleife die Daten ändern und gleichzeitig bei jeder Änderung neu zeichnen (--> Animation). Starte ich die Schleife mit Programmbeginn, funktioniert es wunderbar. Ich möchte die Schleife aber per Button (also im ActionListener) starten, was jetzt nicht mehr funktioniert, d.h. die Schleife läuft zwar durch aber die ständigen Änderungen lösen kein Neuzeichnen aus. Erst am Ende sind alle Daten gezeichnet.
Woran könnte das liegen? Ich hoffe ihr könnt mir helfen. Sonstige Verbesserungsvorschläge jederzeit gerne.

Hier die relevanten Codes:

die Datenstruktur:

```
public class FunHash extends Observable
{
    List[] hashTabelle = new ArrayList[15];
    int[] pool = new int[50];
    ...

    public void setValue(int hashWert, String eingabe)     // wird verwendet für manuelle Dateneingabe
    {
        hashTabelle[hashWert].add(0,eingabe);
        // hier Observer informieren
        this.setChanged();
        this.notifyObservers(this);
    }
		
    public void setValue(int hashWert, Integer pool_elem)
    {
        hashTabelle[hashWert].add(0,pool_elem.toString());
        System.out.println(hashTabelle[hashWert].get(0));
        // hier Observer informieren
        this.setChanged();
        this.notifyObservers(this);
        try{Thread.sleep(100);}catch(Exception e){e.printStackTrace();}    //für eine animierte Darstellung
    }			
    public void poolHashing()
    {
        Vector<Integer> v_pool = new Vector<Integer>();
        for (int i = 0; i < pool.length; i++) 
        {
            v_pool.addElement(new Integer(i));
        }
        for (int j = pool.length; j >= 1; j--) 
        {
            int zufall = (int) (Math.random() * j);
            Integer i = (Integer)v_pool.elementAt(zufall);
            v_pool.removeElementAt(zufall);
            int hashWert = this.hashFunktion(i);
            this.setValue(hashWert, i);	//speichern
        }
    }
}
```

der Listener:

```
public class PoolSpeichernListener implements ActionListener
{
    private FunHash fh;
    private VisPaintPanel paintPanel;

    public void actionPerformed(ActionEvent event)
    {
        JButton sender = (JButton) event.getSource();
        VisGUI top = (VisGUI) sender.getTopLevelAncestor();
        fh = top.getFunHash();				
        paintPanel = top.getVisPaintPanel();
        fh.poolHashing();
    }
}
```

der Observer:

```
public class VisPaintPanel extends JPanel implements Observer
{
    private FunHash fh;
    private Graphics2D g2d;
    private JButton poolHash;

    public VisPaintPanel(FunHash fh)
    {
        this.fh = fh;
        fh.addObserver(this);
        poolHash = new JButton("PoolHash");
        poolHash.addActionListener(new PoolSpeichernListener());
        this.add(poolHash);
    }

    public void paint(Graphics g)
    {
        super.paint(g);	        //löscht Zeichenfläche vor nächstem zeichnen
        g2d = (Graphics2D) g;
        ...                             //Daten aus FunHash zeichen
    }

    public void update(Observable o, Object arg)	//wird durch notify aufgerufen	
    {
        repaint();	//ruft paint() auf --> neuzeichnen
    }
}
```

Dann gibt es noch die Main-Klasse (JFrame) die VisPaintPanel und FunHash erzeugt.


----------



## Guest (11. Nov 2007)

Versuch mal das
	
	
	
	





```
public class PoolSpeichernListener implements ActionListener
{
    public void actionPerformed(ActionEvent event)
    {
        JButton sender = (JButton) event.getSource();
        VisGUI top = (VisGUI) sender.getTopLevelAncestor();

        final FunHash fh = top.getFunHash();
        SwingUtilities.invokeLater(
           new Runnable() {
              public void run() {
                 fh.poolHashing();
              }
           }
        );
    }
}
```


----------



## andyle (11. Nov 2007)

Danke für den Vorschlag. Hat aber leider nichts geändert.


----------



## Quaxli (12. Nov 2007)

Grundsätzlich solltest Du bei Swing das Neuzeichnen in einem eigenen Thread durchführen, sonst wirst Du auf keinen grünen Zweig kommen. Ich würde etwa so vorgehen:

Schon bei Programmstart startest Du einen eigenen Thread der periodisch auf Deine Oberfläche einen repaint startet.

Etwa so:


```
while(running){      //running ist ein boolean

    if(GUI.button_pressed){   //noch'n boolean
       GUI.computeChanges();
    }

     GUI.repaint();
       
      try {
	Thread.sleep(10);
     } catch (InterruptedException e) {}	 

  }
```

In Deiner Gui setzt Du mit dem Button-Click nur einen Boolean, der dem Programm mitteilt, daß Du jetzt die Animation gestartet haben möchtest.
In dem neuen Thread fragst Du diesen Boolean ab um die Änderungen zu berechnen,  die Du dann dargestellt haben möchtest. 
Grundsätzlich bei jedem Schleifendurchlauf rufst Du einen repaint() auf. Anschließend legst Du den Thread für 10 ms schlafen, damit er nicht alles andere blockiert.

Wenn das nicht funzt, poste mal den Code, wo Du jetzt noch Pünktchen (...) stehen hast.

Noch ein Tipp:
Anstelle der paint-Methode würde ich im JPanel die paintComponent-Methode überschreiben. Damit schaltest Du noch ein paar mögliche Probleme auf (vgl. Beschreibung API).[/code]


----------



## J.C. (12. Nov 2007)

Als zusätzliche Info: Wenn sich eine Komponente verändert führt java ein repaint automatisch aus.


----------

