2012-11-19 18 views
5

Ho un codice del genere:repaint() in Java non "ri-dipinge" immediatamente?

// In MyPanel.java 
public void paintComponent(Graphics g) 
{ 
    super.paintComponent(g); 
    // Draw something 
    mypanel_count++; 
} 

// In Test.java 
public void testLargeData() 
{ 
    while (notDone) 
    { 
     panel.repaint(); 
     // do huge work 
     test_count++; 
     System.out.println("Test_count: " + test_count + ", MyPanel_count: " + mypanel_count); 
    } 
} 

// Output !!! 
Test_count: 752, MyPanel_count: 23 
Test_count: 753, MyPanel_count: 23 
Test_count: 754, MyPanel_count: 23 
Test_count: 755, MyPanel_count: 24 

Ma quando cambio panel.repaint() al panel.paintComponent(panel.getGraphics()), il fuori è giusto:

Test_count: 752, MyPanel_count: 752 
Test_count: 753, MyPanel_count: 753 
Test_count: 754, MyPanel_count: 754 
Test_count: 755, MyPanel_count: 755 

Perché? Il metodo paintComponent funziona, ma a volte è cieco, quindi non voglio usarlo. Qualcuno può darmi qualche suggerimento? Grazie!

+0

http://stackoverflow.com/questions/9389187/difference-travel-componente-in-componente-e-pompetenti-in-swing. – Raghunandan

+0

@Raghunandan: grazie per la tua risposta, ma non è un problema mio. –

+0

hai provato [JComponent.html # paintImmediately (int, int, int, int)] (http://docs.oracle.com/javase/6/docs/api/javax/swing/JComponent.html#paintImmediately%28int ,% 20int,% 20int,% 20int% 29) – mKorbel

risposta

9

Se leggete la documentazione di repaint con attenzione, si noterà che si afferma che (sottolineatura mia):

Se questo componente è un componente leggero, questo metodo provoca un chiamata al metodo paint di questa componente nel più breve tempo possibile. Altrimenti, questo metodo provoca una chiamata al metodo di aggiornamento di questo componente non appena possibile.

Ciò significa che AWT/Swing è autorizzato a ottimizzare il ridisegno mediante la fusione di ripetizioni richieste in rapida successione. Esiste anche un metodo repaint(long time), che consente di controllare per quanto tempo AWT/Swing è in grado di attendere con il completamento della richiesta di repaint. Potrebbe comunque unire le richieste, specialmente se le si fa in un ciclo.

Potrebbe essere utile leggere l'articolo "Painting in AWT and Swing", che tenta di spiegare i vari concetti coinvolti.

Per ottenere il pannello ridipinto per ogni iterazione, è necessario attendere che si verifichi una vernice e quindi procedere con il ciclo. Ciò significa che è necessaria una sincronizzazione tra il thread di elaborazione (il loop) e il thread AWT/Swing. Come idea approssimativa, è possibile ad esempio wait() sull'oggetto pannello alla fine del ciclo se non è stato ridipinto dall'ultima chiamata a repaint() e chiamare notifyAll() alla fine del metodo paintComponent() del pannello. Tuttavia, questo può essere difficile da implementare correttamente, quindi dovresti farlo solo se hai davvero bisogno di un "nuovo tempo" per ridisegnare il tuo componente. In alternativa, paintImmediately(...) potrebbe essere utilizzato, ma si dovrebbe fare tutto il vostro processo nel thread dispacciamento evento, in questo modo:

SwingUtilities.invokeLater(new Runnable() { 
    public void run() { 
     while(notDone) { 
      // Do your processing 
      panel.paintImmediately(...); 
     } 
    } 
}); 

Si noti che questo interromperà qualsiasi elaborazione di eventi tra cui mouse e input da tastiera da in fase di elaborazione mentre il tuo ciclo è in esecuzione. Puoi leggere ulteriori informazioni su Swing e Threading in "Concurrency in Swing"

0

capire che non si ha il controllo completo su se o quando vernice (...) ottenere di chiamata, e che repaint() le chiamate sono solo una suggerimento per la JVM di dipingere. Se troppi repaint() richieste arrivano in e stack up come la tua stanno facendo, allora saranno combinati

riferimento: https://stackoverflow.com/a/13256847/1423083

1

Come le altre risposte dicono: è un problema di quando AWT chiama paint().

Se si esegue un lavoro che richiede informazioni dai componenti dipinti/impaginati, ciò che aiuta è anche inserire questo lavoro in un thread di lavoro che attende fino a quando il disegno non viene eseguito.

Nel tuo caso, che sarebbe qualcosa di simile:

panel.repaint(); 

SwingUtilities.invokeLater(new Runnable() { 
    public void run() { 
     // do huge work 
     test_count++; 
     System.out.println("Test_count: " + test_count 
      + ", MyPanel_count: " + mypanel_count); 
    } 
}); 

Anche se non sono sicuro di come si comporterebbe nel vostro while ciclo.