2010-12-09 12 views
4

Ich versuche ein Programm in Java zu erstellen, das hintereinander eine Reihe von Bildern anzeigt, die die Größe des Rahmens für jeden anpassen. ich JPanel erstreckt, ein Bild wie folgt angezeigt:Java warte auf die Komponente, die gemalt werden soll

public class ImagePanel extends JPanel{ 

String filename; 
Image image; 
boolean loaded = false; 

ImagePanel(){} 

ImagePanel(String filename){ 
    loadImage(filename); 
} 

public void paintComponent(Graphics g){ 
    super.paintComponent(g); 
    if(image != null && loaded){ 
     g.drawImage(image, 0, 0, this); 
    }else{ 
     g.drawString("Image read error", 10, getHeight() - 10); 
    } 
} 

public void loadImage(String filename){ 
    loaded = false;   
    ImageIcon icon = new ImageIcon(filename); 
    image = icon.getImage(); 
    int w = image.getWidth(this); 
    int h = image.getHeight(this); 
    if(w != -1 && w != 0 && h != -1 && h != 0){ 
     setPreferredSize(new Dimension(w, h)); 
     loaded = true; 
    }else{ 
     setPreferredSize(new Dimension(300, 300)); 
    } 
} 

}

Dann in Event Thread tun Ich bin Hauptarbeit:

 SwingUtilities.invokeLater(new Runnable(){ 

     @Override 
     public void run(){ 
      createGUI(); 
     } 
    }); 

In createGUI() Ich bin Gehen Sie durch die Menge der Bilder:

 ImagePanel imgPan = new ImagePanel(); 
    add(imgPan); 

    for(File file : files){ 
     if(file.isFile()){ 
      System.out.println(file.getAbsolutePath()); 

      imgPan.loadImage(file.getAbsolutePath()); 
      pack(); 

      try { 
       Thread.sleep(500); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 
    } 

Das Problem ist, dass mein Programm die Größenänderung p Roperly, also Bilder werden korrekt geladen, aber es zeigt nichts an. Wenn ich nur 1 Bild anzeigen, funktioniert es auch für das letzte Bild. Ich denke, das Problem ist, dass Thread.sleep() aufgerufen wird, bevor das Bildmalen beendet ist.

Wie kann ich warten, bis mein ImagePanel fertig ist und danach wartet? Oder gibt es einen anderen Weg, um das Problem zu lösen?

Danke! Leonty

Antwort

4

Der gesamte Code wird auf dem Event Dispatch Thread ausgeführt. Dies bewirkt effektiv, dass alle Benutzerinteraktionen inaktiv sind, da der Event Dispatch-Thread für alle Benutzerinteraktionen verantwortlich ist - sowohl für die Eingabe (Ereignisse) als auch für die Ausgabe (Malen).

Sie müssen warten, um außerhalb des EDT passieren. Sie müssen wissen, wie Sie Ereignisse an und von der EDT ausführen. Sie tun dies, indem Sie eine neue Runnable erstellen und dann entweder new Thread(runnable) aufrufen, um sie von der EDT oder SwingUtilities.invokeLater(runnable) auszuführen, damit sie auf der EDT ausgeführt wird. Alle Interaktionen mit Swing-Komponenten müssen auf dem EDT stattfinden, da Swing-Objekte nicht Thread-sicher sind. Alle schlafenden, wartenden, Dateizugriffs-, Netzwerkzugriffs-, Datenbankzugriffs- oder sonstigen Vorgänge, die möglicherweise für unbestimmte Zeit blockiert sind, müssen außerhalb des EDT stattfinden.

Es gibt viele Fragen zu Stack Overflow, die mit dem Event Dispatch Thread zu tun haben. Ich empfehle Ihnen, diese zu überprüfen, um mehr Informationen und Codebeispiele zu finden, um das zu tun, was Sie auf unterschiedliche Weise tun möchten.

+0

Danke! Das hat mich auf den richtigen Weg gebracht! Ich führe jetzt Code im Hauptthread aus und alle Operationen sind jetzt synchron, so dass das Warten erst nach dem Ende des Malens erfolgt. – Leonti

1

Anstatt den Thread schlafen zu lassen, verwenden Sie einen Timer und starten Sie das nächste Bild als Ereignis.

+0

ich versucht, und es hat funktioniert, aber ich brauchte pack() zu verwenden, Fenster für jedes Bild, um die Größe und I:

Ihr Problem zu lösen, werde ich Ihnen eine Unterklasse von SwingWorker wie vorschlagen erstellen hatte das gleiche Problem - ich musste wissen, wann das Malen beendet ist, um 'pack()' zu nennen. – Leonti

1

Es hört sich so an, als würden Bilder nacheinander angezeigt werden, wenn sie geladen werden (zB wie auf einer Webseite), ist das korrekt? Wenn dies der Fall ist, würden Sie diesen Effekt nicht mit Ihrem aktuellen Code erzielen, da Ihre Benutzeroberfläche erst dann aktualisiert wird, wenn alle Bilder geladen sind. Dies liegt daran, dass Sie Bilder auf EDT (Event Dispatch Thread) laden, bei dem es sich um denselben Thread handelt. Ich werde das Gemälde machen. Malen geschieht "wenn Zeit ist", was in diesem Fall bedeutet, dass alle Bilder geladen sind.

public class MyImageLoader extends SwingWorker<Void, String> 
{ 
    // Is executed in background thread, EDT can meanwhile load and paint images 
    @Override 
    protected Void doInBackground() throws Exception 
    { 
     for(File file : files) 
     { 
      if(file.isFile()) // Maybe some more check to see if it's an image 
      { 
       publish(file.getAbsolutePath()); 
       Thread.sleep(500); 
      } 
     } 
    } 

    // Executed on EDT 
    @Override 
    protected void process(List<String> filePaths) 
    { 
     for(String path : filePaths) 
     { 
      // Load ImageIcon to UI 
     } 
    } 
} 
Verwandte Themen