2012-06-17 14 views
14

I sottoclasse JPanel per sovrascrivere paintComponent (Grafica), Voglio disegnare un'immagine su jpanel in una jframe.JPanel non si aggiorna fino a ridimensionare Jframe

Ma la mia immagine non è stata visualizzata fino a quando non apporto le dimensioni di jframe. Questo è il mio codice:

public class ImagePanel extends JPanel{ 

    public void setImage(BufferedImage bi) 
    { 
     image = bi; 
     revalidate(); 
    } 

    @Override 
    public void paintComponent(Graphics g) 
    { 
     super.paintComponent(g); 
     if(image != null) 
     { 
      g.drawImage(image, 0, 0, this); 
     } 
    } 
} 

risposta

7

Se si vuole "rinfrescare" il JPanel allora si dovrebbe chiamare repaint(), che chiamerà il vostro paintComponent(). Questo dovrebbe risolvere il problema:

public void setImage(BufferedImage bi) 
{ 
    image = bi; 
    EventQueue.invokeLater(new Runnable() 
    { 
     public void run() 
     { 
      repaint(); 
     } 
    }); 
} 

sua buona pratica di aggiornare e modificare l'interfaccia grafica utilizzando l'EDT. Ecco maggiori informazioni sul EDT se siete interessati:

How does the event dispatch thread work?

repaint non ha bisogno di essere chiamato dalla EDT. Se stai cambiando la GUI, come ad esempio l'impostazione del testo su una JLabel, dovrebbe essere all'interno dell'EDT. Ecco maggiori informazioni su ciò che può essere definito al di fuori del EDT (per gentile concessione di mucca Nizza):

Safe to use Component.repaint() outside EDT?

+0

Grazie John, funziona perfettamente! – nautilusvn

+1

+1 per il prezioso input. Solo un suggerimento, non c'è bisogno di mettere la chiamata 'repaint()' dentro EDT, dato che è sicuro chiamare 'repaint()' da qualsiasi thread, come descritto [qui] (http://stackoverflow.com/questions/9786497/safe -to-use-component-repaint-outside-edt/9786598 # 9786598) –

+1

"sottoclassi di componenti Swing che hanno un delegato UI ... dovrebbe invocare' super.paintComponent() '" - [* The Paint Methods *] (http: //java.sun.com/products/jfc/tsc/articles/painting/index.html#callback). – trashgod

18

Verificare che si richiama setVisible()dopo aggiunta di componenti e chiamando pack(), come discusso in questo correlati example. Potrebbe anche essere necessario adottare uno layout appropriato. Il richiamo di repaint(), come suggerito here, può risolvere il problema ma non la causa sottostante.

2

Ho avuto lo stesso problema e l'ho risolto con la chiamata setVisible (true); il JFrame che stavo usando.

Esempio: se la JFrame non viene aggiornato dopo l'uso:

jframe.setContentPane(new MyContentPane()); 

fissarlo con:

jframe.setContentPane(new MyContentPane()); 
jframe.setVisible(true); 

So che suona stupido per fare questo anche se il JFrame è già visibile, ma questo è l'unico modo che ho trovato finora per risolvere questo problema (la soluzione sopra proposta non ha funzionato per me).

Ecco un esempio completo. Esegui e decommenta "f.setVisible (true);" istruzioni nelle classi Panel1 e Panel2 e vedrai la differenza. Non dimenticare le importazioni (Ctrl + Shift + O per le importazioni automatiche).

Classe principale:

public class Main { 
    private static JFrame f; 
    public static void main(String[] args) { 
     f = new JFrame(); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.setContentPane(new Panel1(f)); 
     f.pack();  
     f.setVisible(true); 
    } 
} 

Panel1 classe:

public class Panel1 extends JPanel{ 
    private JFrame f; 
    public Panel1(JFrame frame) { 
     f = frame; 
     this.setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS)); 
     JButton b = new JButton("Panel 1"); 
     b.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 
       f.setContentPane(new Panel2(f)); 
       // Uncomment the instruction below to fix GUI "update-on-resize-only" problem 
       //f.setVisible(true); 
      } 
     }); 
     add(b); 
    } 
} 

Panel2 classe:

public class Panel2 extends JPanel{ 
    private JFrame f; 
    public Panel2(JFrame frame) { 
     f = frame; 
     this.setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS)); 
     JButton b = new JButton("Panel 2"); 
     b.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 
       f.setContentPane(new Panel1(f)); 
       // Uncomment the instruction below to fix GUI "update-on-resize-only" problem 
       //f.setVisible(true); 
      } 
     }); 
     add(b); 
    } 
} 

Speranza che aiuta.

Saluti.

+0

Perfetto! Non so perché funzioni, ma è l'unica cosa che ha risolto il mio problema. Prima, stavo facendo questo: Dimension size = frame.getSize(); \t Boolean maximized = frame.getExtendedState() == JFrame.MAXIMIZED_BOTH; \t frame.setSize (new Dimension ((int) size.getWidth() - 1, (int) size.getHeight() - 1)); \t if (maximized) frame.setExtendedState (JFrame.MAXIMIZED_BOTH); \t else frame.setSize (dimensione); La tua risposta è molto, molto più pulita e molto meno hacky. Grazie! – dberm22

+1

@ dberm22 in realtà, non c'è bisogno di hacking (almeno non in questo esempio, non ho verificato l'originale con un'immagine di dimensioni diverse, né stati di dimensioni estese che potrebbero essere ingannevoli): l'impostazione di contentPane è-a modifica della gerarchia del contenitore del frame e come tale richiede una riconvalida sul frame. – kleopatra

5

Date un'occhiata a the docs per JPanel.add(), che eredita da java.awt.Container:

Aggiunge il componente specificato alla fine di questo contenitore. Questo è un metodo comodo per addImpl (java.awt.Component, java.lang.Object, int). Questo metodo modifica le informazioni relative al layout e, pertanto, invalida la gerarchia dei componenti. Se il contenitore è già stato visualizzato, la gerarchia deve essere convalidata successivamente per visualizzare il componente aggiunto.

Enfasi aggiunta.

Pertanto, se si modifica un contenitore dopo che è già stato visualizzato, è must chiamata validate() in modo che esso per vedere. Basta invocare repaint() non è sufficiente. Potresti aver notato che chiamare anche setVisible(true); questo perché it calls validate() internally.

Problemi correlati