2011-08-27 131 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上。 –