2011-08-27 15 views
6

Ho un JFrame che contiene 2 sottoclassi JPanel e 2 JLabel in BorderLayout. Uno dei JPanel contiene JButtons e l'altro è utilizzato per visualizzare la grafica. I JLabels sono a nord ea sud, il bottone JPanel a ovest e il display JPanel al centro.Problema di riverniciatura JPanel

Il display JPanel richiede un aggiornamento costante, quindi invoco il suo metodo repaint() tramite l'evento di azione generato dal timer dello swing. Inoltre, sovrascrivo il suo metodo paintComponent() per fare i miei disegni.

Invece di visualizzare ciò che ho disegnato, il "contenuto di JFrame" viene disegnato sul display JPanel. Sono consapevole che posso semplicemente "cancellare" lo schermo JPanel usando g.fillRect() o super.paintComponent() prima di fare i miei disegni.

Sono solo curioso di sapere perché questo accade.

sto usando jdk 1.6u27. qui di seguito è il mio codice:

package test; 

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 
import javax.swing.event.*; 

public class Main { 

public static void main(String[] args) { 
    Simulation sim = new Simulation(); 

    } 
} 

class Simulation extends JFrame { 

    public JLabel state; 
    private JLabel id; 
    private ButtonPanel control; 
    private Display display; 

    public Simulation() { 
     id = new JLabel("Test"); 
     state = new JLabel("Test"); 
     control = new ButtonPanel(); 
     display = new Display(this); 

     this.setLayout(new BorderLayout()); 
     this.add(id, BorderLayout.NORTH); 
     this.add(control, BorderLayout.WEST); 
     this.add(display, BorderLayout.CENTER); 
     this.add(state, BorderLayout.SOUTH); 

     this.setSize(500, 600); 
     this.setVisible(true); 
     this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

    } 

    public ButtonPanel getControl() { 
     return this.control; 
    } 
} 

class ButtonPanel extends JPanel implements ActionListener { 

    public JButton b[] = new JButton[8]; 
    public boolean bp[] = new boolean[8]; 

    public ButtonPanel() { 
     this.setLayout(new GridLayout(8, 1)); 

     for (int i = 0; i < b.length; i++) { 
      b[i] = new JButton(""+i); 
      b[i].addActionListener(this); 
      bp[i] = false; 
      this.add(b[i]); 
     } 
    } 

    public void actionPerformed(ActionEvent e) { 
     //do something 
    } 
} 

class Display extends JPanel implements ActionListener { 

    private Timer tm; 
    private int yco; 
    private Simulation sim; 

    public Display(Simulation sim) { 
     tm = new Timer(100, this); 
     tm.start(); 

     yco = 0; 

     this.sim = sim; 
    } 

    @Override 
    public void paintComponent(Graphics g) { 
     //draw something 
     g.drawLine(0, yco, 100, 100); 
    } 

    public void actionPerformed(ActionEvent e) { 
     yco ++; 
     this.repaint(); 
    } 
} 

screenshot

+0

+1 per [sscce] (http://sscce.org/). – trashgod

risposta

9

Senza super.paintComponent(g), il risultato dipende dalla impostazione predefinita della vostra piattaforma per la opacity di proprietà del delegato JPanel UI, PanelUI. Il mio è lo true, ma puoi sperimentare sulla tua piattaforma, come suggerito di seguito.

Addendum: "Se non si rispetta lo opaque property è probabile che si veda l'immagine artifacts." - paintComponent(). Lo artifact che osservi varierà in base alla piattaforma, ma non è atipico. In effetti, si sta rompendo la promessa di disegnare ogni pixel, e si vede tutto ciò che è rimasto in un buffer.

Main

import java.awt.*; 
import java.awt.event.*; 
import java.util.ArrayList; 
import java.util.List; 
import javax.swing.*; 

public class Main { 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       Simulation sim = new Simulation(); 
      } 
     }); 
    } 
} 

class Simulation extends JFrame { 

    public JCheckBox state; 
    private JLabel id; 
    private ButtonPanel control; 
    private Display display; 

    public Simulation() { 
     id = new JLabel("Test"); 
     state = new JCheckBox("Opaque"); 
     control = new ButtonPanel(); 
     display = new Display(this); 

     this.setLayout(new BorderLayout()); 
     this.add(id, BorderLayout.NORTH); 
     this.add(control, BorderLayout.WEST); 
     this.add(display, BorderLayout.CENTER); 
     this.add(state, BorderLayout.SOUTH); 
     state.addItemListener(new ItemListener() { 

      @Override 
      public void itemStateChanged(ItemEvent e) { 
       display.setOpaque(e.getStateChange() == ItemEvent.SELECTED); 
      } 
     }); 
     state.setSelected(true); 

     this.pack(); 
     this.setVisible(true); 
     this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    } 

    public ButtonPanel getControl() { 
     return this.control; 
    } 
} 

class ButtonPanel extends JPanel { 

    private static final int N = 8; 
    private List<JToggleButton> list = new ArrayList<JToggleButton>(N); 

    public ButtonPanel() { 
     this.setLayout(new GridLayout(0, 1)); 
     for (int i = 0; i < N; i++) { 
      final JToggleButton b = new JToggleButton(String.valueOf(i)); 
      b.addActionListener(new ActionListener() { 

       @Override 
       public void actionPerformed(ActionEvent e) { 
        //System.out.println(b.isSelected()); 
       } 
      }); 
      list.add(b); 
      this.add(b); 
     } 
    } 
} 

class Display extends JPanel { 

    private Simulation sim; 
    private Timer tm; 
    private int yco; 

    public Display(Simulation sim) { 
     this.setPreferredSize(new Dimension(320, 320)); 
     this.setOpaque(true); 
     this.sim = sim; 
     tm = new Timer(100, new ActionListener() { 

      @Override 
      public void actionPerformed(ActionEvent e) { 
       yco++; 
       repaint(); 
      } 
     }); 
     tm.start(); 
    } 

    @Override 
    public void paintComponent(Graphics g) { 
     //super.paintComponent(g); 
     g.drawLine(0, yco, getWidth()/2, getHeight()/2); 
    } 
} 
+1

In generale, dovresti chiamare 'super.paintComponent (g)' o "i discendenti leggeri del contenitore non verranno visualizzati". – trashgod

+2

Vedere anche [Discussione principale contro thread UI in Java] (http://stackoverflow.com/questions/7156949/main-thread-vs-ui-thread-in-java/7158505#7158505). – trashgod

+0

Vedo, non sapevo che esistesse una tale opzione, grazie per la spiegazione. Ma il mio problema è in realtà il contenuto del JFrame viene disegnato sul display JPanel. Ad esempio, l'etichetta superiore e i pulsanti laterali vengono disegnati sullo schermo JPanel, insieme a quelle linee nere. –