2012-04-09 2 views
3

so versuche ich eine Anwendung einzurichten, wo ich mehrere Panels in einem Jframe haben. Nehmen wir an, drei von ihnen dienen lediglich der Anzeige, und einer davon dient der Kontrolle. Ich benutze ein BorderLayout, aber ich denke nicht, dass das Layout die Dinge hier wirklich beeinflussen sollte.Repainting mehrere JPanel von einem einzigen "Control" -Panel

mein Problem ist dies: Ich möchte die Neuanstrich der drei Anzeigefelder unter der Kontrolle der Tasten in der Systemsteuerung, und ich möchte sie alle synchron ausführen, wenn eine Taste auf dem Bedienfeld gedrückt wird. dies zu tun, habe ich diese kleine Methode auf:

public void update(){ 
      while(ButtonIsOn){ 
       a.repaint(); 
       b.repaint() 
       c.repaint(); 
       System.out.println("a,b, and c should have repainted"); 

       } 
    } 

wobei a, b und c sind alle Anzeigetafeln und ich möchte, a, b und c, um alle ständig neu streichen, bis ich die Taste erneut drücken. Das Problem ist, wenn ich die Schleife ausfühle, druckt die Nachricht in einer Endlosschleife, aber keiner der Panels tut irgendetwas, dh, keiner von ihnen streicht neu.

Ich habe auf dem Event-Versand-Thread lesen und Multithreading schwingen, aber nichts, was ich bis jetzt gefunden habe, hat wirklich mein Problem gelöst. Könnte jemand mir den Kern dessen geben, was ich hier falsch mache, oder noch besser, ein Beispielcode, der die Situation behandelt, die ich beschreibe? Danke ...

+0

* * Für eine bessere Hilfe früher, bucht einen [SSCCE] (http ".. einiger Beispielcode, der die Situation behandelt i beschreiben bin?": // sscce. org /). –

+1

Bitte lernen Sie Java-Namenskonventionen und halten Sie sich daran. – kleopatra

+1

Was genau ist das Problem (abgesehen von Ihrer Endlosschleife, die dadurch verursacht wird, dass der Boolean, der die while steuert, nicht zurückgesetzt wird)? Wie genau macht das _none der Panels irgendetwas, dh keiner von ihnen repaint_ manifest? – kleopatra

Antwort

2

Das Paket java.util.concurrent bietet sehr leistungsfähige Tools für die gleichzeitige Programmierung.

Im folgenden Code verwende ich eine ReentrantLock (die ähnlich wie das Java synchronized Schlüsselwort funktioniert, wodurch sich gegenseitig ausschließender Zugriff durch mehrere Threads auf einen einzelnen Codeblock gewährleistet). Die andere großartige Sache, die ReentrantLock bietet, sind Conditions, die Threads erlauben, auf ein bestimmtes Ereignis zu warten, bevor Sie fortfahren.

Hier RepaintManager einfach loops, ruft repaint() auf der JPanel. Wenn jedoch toggleRepaintMode() aufgerufen wird, blockiert es und wartet auf die modeChanged Condition bis toggleRepaintMode() erneut aufgerufen wird.

Sie sollten den folgenden Code direkt aus der Box ausführen können. Drücken Sie die JButton toggle Neuanstrich der JPanel (die Sie durch die System.out.println Anweisungen arbeiten sehen können).

Im Allgemeinen würde ich sehr empfehlen, sich mit den Fähigkeiten vertraut zu machen, die java.util.concurrent bietet.Da sind viele sehr mächtige Sachen. Es gibt ein gutes Tutorial auf http://docs.oracle.com/javase/tutorial/essential/concurrency/

import java.awt.Component; 
import java.awt.Graphics; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.util.Collection; 
import java.util.Collections; 
import java.util.concurrent.locks.Condition; 
import java.util.concurrent.locks.ReentrantLock; 

import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 

public class RepaintTest { 
    public static void main(String[] args) { 

     JFrame frame = new JFrame(); 
     JPanel panel = new JPanel() 
     { 
      @Override 
      public void paintComponent(Graphics g) 
      { 
       super.paintComponent(g); 

       // print something when the JPanel repaints 
       // so that we know things are working 
       System.out.println("repainting"); 
      } 
     }; 

     frame.add(panel); 

     final JButton button = new JButton("Button"); 
     panel.add(button); 

     // create and start an instance of our custom 
     // RepaintThread, defined below 
     final RepaintThread thread = new RepaintThread(Collections.singletonList(panel)); 
     thread.start(); 

     // add an ActionListener to the JButton 
     // which turns on and off the RepaintThread 
     button.addActionListener(new ActionListener() { 

      @Override 
      public void actionPerformed(ActionEvent arg0) { 
       thread.toggleRepaintMode(); 
      } 
     }); 

     frame.setSize(300, 300); 
     frame.setVisible(true); 
    } 

    public static class RepaintThread extends Thread 
    { 
     ReentrantLock lock; 
     Condition modeChanged; 
     boolean repaintMode; 
     Collection<? extends Component> list; 

     public RepaintThread(Collection<? extends Component> list) 
     { 
      this.lock = new ReentrantLock(); 
      this.modeChanged = this.lock.newCondition(); 

      this.repaintMode = false; 
      this.list = list; 
     } 

     @Override 
     public void run() 
     { 
      while(true) 
      { 
       lock.lock(); 
       try 
       { 
        // if repaintMode is false, wait until 
        // Condition.signal() is called 
        while (!repaintMode) 
         try { modeChanged.await(); } catch (InterruptedException e) { } 
       } 
       finally 
       { 
        lock.unlock(); 
       } 

       // call repaint on all the Components 
       // we're not on the event dispatch thread, but 
       // repaint() is safe to call from any thread 
       for (Component c : list) c.repaint(); 

       // wait a bit 
       try { Thread.sleep(50); } catch (InterruptedException e) { } 
      } 
     } 

     public void toggleRepaintMode() 
     { 
      lock.lock(); 
      try 
      { 
       // update the repaint mode and notify anyone 
       // awaiting on the Condition that repaintMode has changed 
       this.repaintMode = !this.repaintMode; 
       this.modeChanged.signalAll(); 
      } 
      finally 
      { 
       lock.unlock(); 
      } 
     } 
    } 
} 
+0

danke. also funktioniert das irgendwie wie ein Monitor oder Semaphor? – russell88

+0

Richtig, 'ReentrantLock' funktioniert sehr ähnlich wie ein * Monitor * oder * Semaphor * mit einer Anzahl von 1 (dh ein * Mutex *) oder das * synchronisierte * Schlüsselwort, da es garantiert, dass nur ein einzelner Thread in der Lage ist Greifen Sie gleichzeitig auf den Codeblock zu, den er schützt. – ulmangt

+0

In diesem Fall ist es auch schön, weil die Verwendung einer 'Condition' bedeutet, dass die 'RepaintThread'-Klasse nicht * beschäftigt sein muss, * wenn das Neuzeichnen ausgeschaltet ist. Es kann einfach 'Condition.await()' aufrufen und dann blockiert der Thread, ohne CPU-Zyklen zu verschwenden, bis 'Condition.signal()' aufgerufen wird. – ulmangt

0

Sie könnten dafür SwingWorker verwenden. SwingWorker wurde entwickelt, um lange laufende Aufgaben im Hintergrund auszuführen, ohne den Event-Dispatcher-Thread zu blockieren. Sie müssen also SwingWorker erweitern und bestimmte Methoden implementieren, die für Sie sinnvoll sind. Beachten Sie, dass alle lang andauernden Aktionen in der Methode doInBackground() ausgeführt werden sollten und dass die Swing-UI-Elemente nur für die Methode done() aktualisiert werden sollten.

So, hier ist ein Beispiel:

class JPanelTask extends SwingWorker<String, Object>{ 
    JPanel panel = null; 
    Color bg = null; 
    public JPanelTask(JPanel panel){ 
     this.panel = panel; 
    } 
    @Override 
    protected String doInBackground() throws Exception { 
     //loooong running computation. 
     return "COMPLETE"; 
    } 
    @Override 
    protected void done() { 
     panel.repaint(); 
    } 

} 

nun in Ihrem "Kontrolle" auszuführende Aktion-Ereignis der Schaltfläche, Sie folgendermaßen vorgehen könnte:

controlButton.addActionListener(new ActionListener() { 

     @Override 
     public void actionPerformed(ActionEvent arg0) { 
      JPanelTask task1 = new JPanelTask(panel1); 
      task1.execute(); 
      JPanelTask task2 = new JPanelTask(panel2); 
      task2.execute(); 
      //so on.. 
     } 
    }); 

Ein anderer Weg javax.swing.Timer verwendet. Timer hilft Ihnen, eine Änderung an Ihren Elementen in einer fristhion fire.hion.This möglicherweise nicht die am besten geeignete Lösung. Aber es macht auch die Arbeit erledigt. Wieder sollten Sie vorsichtig sein, wenn Sie UI-Elemente an den richtigen Stellen aktualisieren.

1
jComponent.getTopLevelAncestor().repaint(); 
Verwandte Themen