2011-08-27 129 views
6

我有一个JFrame在BorderLayout中包含2个JPanel子类和2个JLabel。其中一个JPanel包含JButton,另一个用于显示图形。 JLabels位于北部和南部,西部的按钮JPanel和中央的显示器JPanel。JPanel重绘问题

显示器JPanel需要不断刷新,所以我通过swing定时器生成的动作事件调用repaint()方法。我也重写它的paintComponent()方法来完成我的绘图。

而不是显示我画的内容,“JFrame的内容”正被绘制到显示器JPanel上。我知道在执行绘图之前,我可以通过使用g.fillRect()或super.paintComponent()来简单地“清除”显示JPanel。

我只是好奇为什么会发生这种情况。

我使用jdk 1.6u27。下面是我的代码:

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为[SSCCE](http://sscce.org/)。 – trashgod

回答

9

没有super.paintComponent(g),结果取决于你的平台默认为JPanel UI委托,PanelUIopacity财产。我碰巧是true,但您可以在您的平台上进行试验,如下所示。

附录:“如果您不尊重opaque property,您可能会看到视觉artifacts。” - paintComponent()。您观察到的artifact将因平台而异,但它不是非典型的。实际上,您违背了绘制每个像素的承诺,并且您会看到某些缓冲区中剩下的内容。

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

一般来说,你应该调用'super.paintComponent(g)'或者“容器的轻量级后代不会出现。” – trashgod

+2

另请参见[主线程与Java中的UI线程](http://stackoverflow.com/questions/7156949/main-thread-vs-ui-thread-in-java/7158505#7158505)。 – trashgod

+0

我明白了,我不知道有这样的选择,谢谢你的解释。但我的问题实际上是JFrame的内容被绘制到显示器JPanel上。例如,顶部标签和侧面按钮与黑色线一起被绘制到显示器JPanel上。 –