2013-07-04 56 views
0

我想編寫一個自定義的JPanel,它遵循包含JPanel的layoutmanager(我正在使用gridbag)。我的自定義JPanel在這裏粘貼時間有點過長,但需要覆蓋所有方法的清單才能使其工作。編寫將遵循LayoutManager規範的自定義JPanel

這裏是我的自定義JPanel的摘錄:

 public class GridPanel extends JPanel implements MouseMotionListener, MouseListener{ 
      private Rectangle offdutyRect, sbRect, driveRect, onRect; 
      private int delta = 60; 
      private int[][] gridArray; 
      int draggedStartX = -1; 
      int draggedStartY = -1; 
      private int dutyStatusSpacing = 60; 
      private int totalSpacing = 100; 

      public GridPanel(){ 
      this.setSize(new Dimension(800, 100)); 
      this.addMouseMotionListener((MouseMotionListener) this); 
      this.addMouseListener(this); 
      int gridArrayColumns = 24*60/delta; 
      gridArray = new int[4][gridArrayColumns]; 

      int r = 0; 
      int rHeight = this.getHeight()/4; 
      offdutyRect = new Rectangle(this.getX() + dutyStatusSpacing, this.getY() + r*rHeight, this.getWidth() - totalSpacing, rHeight); 
      r++; 
      sbRect = new Rectangle(this.getX() + dutyStatusSpacing, this.getY() + r*rHeight, this.getWidth() - totalSpacing, rHeight); 
      r++; 
      driveRect = new Rectangle(this.getX() + dutyStatusSpacing, this.getY() + r*rHeight, this.getWidth() - totalSpacing, rHeight); 
      r++; 
      onRect = new Rectangle(this.getX() + dutyStatusSpacing, this.getY() + r*rHeight, this.getWidth() - totalSpacing, rHeight); 

      Rectangle rect = null; 
      for(r = 0; r < gridArray.length; r++){ 
       if(r == 0){ 
       rect = offdutyRect; 
       }else if(r == 1){ 
       rect = sbRect; 
       }else if(r == 2){ 
       rect = driveRect; 
       }else if(r == 3){ 
       rect = onRect; 
       } 

       //I haven't actually derived any of these things, just my best guesses. 
       int len = gridArray[r].length; 
       int width = (int) (rect.getWidth()/len); 
       rect.setSize((int)(width*len), (int) rect.getHeight()); 
      } 
     } 

    public void paintComponent(Graphics g){ 
     g.clearRect(this.getX(), this.getY(), this.getWidth(), this.getHeight()); 
     //the center black bar for duty status "placeholders" 
     g.setColor(Color.black); 
     g.drawRect(getX(), getY(), getWidth() - 1, getHeight() - 1); 
     g.drawRect((int)offdutyRect.getX(), (int)offdutyRect.getY() + (int)offdutyRect.getHeight()/2, (int)offdutyRect.getWidth(), 1); 
     g.drawRect((int)sbRect.getX(), (int)sbRect.getY() + (int)sbRect.getHeight()/2, (int)sbRect.getWidth(), 1); 
     g.drawRect((int)driveRect.getX(), (int)driveRect.getY() + (int)driveRect.getHeight()/2, (int)driveRect.getWidth(), 1); 
     g.drawRect((int)onRect.getX(), (int)onRect.getY() + (int)onRect.getHeight()/2, (int)onRect.getWidth(), 1); 
     g.setColor(Color.pink); 
     g.drawRect((int)offdutyRect.getX(), (int)offdutyRect.getY(), (int)offdutyRect.getWidth(), (int)offdutyRect.getHeight()); 
     g.drawRect((int)sbRect.getX(), (int)sbRect.getY(), (int)sbRect.getWidth(), (int)sbRect.getHeight()); 
     g.drawRect((int)driveRect.getX(), (int)driveRect.getY(), (int)driveRect.getWidth(), (int)driveRect.getHeight()); 
     g.drawRect((int)onRect.getX(), (int)onRect.getY(), (int)onRect.getWidth(), (int)onRect.getHeight()); 

     //draw the array 
     g.setColor(Color.green); 
     Rectangle rect = null; 
     for(int r = 0; r < gridArray.length; r++){ 
      if(r == 0){ 
      rect = offdutyRect; 
      }else if(r == 1){ 
      rect = sbRect; 
      }else if(r == 2){ 
      rect = driveRect; 
      }else if(r == 3){ 
      rect = onRect; 
      } 

      //I haven't actually derived any of these things, just my best guesses. 
      int len = gridArray[r].length; 
      int width = (int) (rect.getWidth()/len); 

      int height = (int) rect.getHeight() - 2; 
      for(int c = 0; c < gridArray[r].length; c++){ 
      if(gridArray[r][c] == 1){ 
        int x = (int) (rect.getX() + width*c); 
        int y = (int) rect.getY() + 2; 
        g.fillRect(x, y, width, height); 
      } 
      } 
     } 
     } 
    //implement setSize 
    public void setSize(Dimension d){ 

    if(gridArray == null){ 

     int gridArrayColumns = 24*60/delta; 
     gridArray = new int[4][gridArrayColumns]; 
    } 
    int r = 0; 
    int rHeight = this.getHeight()/4; 
    offdutyRect = new Rectangle(this.getX() + dutyStatusSpacing, this.getY() + r*rHeight, (int)d.getWidth() - totalSpacing, rHeight); 
    r++; 
    sbRect = new Rectangle(this.getX() + dutyStatusSpacing, this.getY() + r*rHeight, (int)d.getWidth() - totalSpacing, rHeight); 
    r++; 
    driveRect = new Rectangle(this.getX() + dutyStatusSpacing, this.getY() + r*rHeight, (int)d.getWidth() - totalSpacing, rHeight); 
    r++; 
    onRect = new Rectangle(this.getX() + dutyStatusSpacing, this.getY() + r*rHeight, (int)d.getWidth() - totalSpacing, rHeight); 

    Rectangle rect = null; 
    for(r = 0; r < gridArray.length; r++){ 
     if(r == 0){ 
     rect = offdutyRect; 
     }else if(r == 1){ 
     rect = sbRect; 
     }else if(r == 2){ 
     rect = driveRect; 
     }else if(r == 3){ 
     rect = onRect; 
     } 

     //I haven't actually derived any of these things, just my best guesses. 
     int len = gridArray[r].length; 
     int width = (int) (rect.getWidth()/len); 
     rect.setSize((int)(width*len), (int) rect.getHeight()); 
    } 
    } 

} 

這裏是相對較短的定製容器,我的自定義類的多個實例將被添加:

public class GridContainer extends JPanel implements ActionListener{ 
    List<GridPanel> panels = new ArrayList<GridPanel>(); 

    public GridContainer(){ 
    GridBagLayout gb = new GridBagLayout(); 
    this.setLayout(gb); 
    GridBagConstraints c = new GridBagConstraints(); 

    c.gridx = 0; 
    c.gridy = 0; 
    c.weightx = .5; 
    c.weighty = .5; 
    c.fill = GridBagConstraints.HORIZONTAL; 
    BufferedImage img = null; 
    try { 
     img = ImageIO.read(this.getClass().getResource("/res/add.png")); 
    } catch (IOException e) { } 
    JButton addButton = new JButton(); 
    addButton.setIcon(new ImageIcon(img)); 
    addButton.addActionListener(this); 
    this.add(addButton, c); 
    } 

    public void actionPerformed(ActionEvent e) { 
    System.out.println("action performed" + panels.size()); 
    this.setLayout(new GridBagLayout()); 
    removeAll(); 
    repaint(); 
    panels.add(new GridPanel()); 
    int r = 0; 
    GridBagConstraints c = new GridBagConstraints(); 
    for(int i = 0; i < panels.size(); i++){ 
      JLabel label = new JLabel("day " + i); 
      c = new GridBagConstraints(); 
      c.gridx = 0; 
      c.gridy = r; 
      c.weightx = 1; 
      c.weighty = 1; 
      this.add(label, c); 
      r++; 

      c = new GridBagConstraints(); 
      c.gridx = 0; 
      c.gridy = r; 
      c.weightx = 1; 
      c.weighty = 1; 
      c.fill = GridBagConstraints.HORIZONTAL; 
      this.add(panels.get(i), c); 
      r++; 
    } 

    c = new GridBagConstraints(); 
    c.gridx = 0; 
    c.gridy = r; 
    c.weightx = 1; 
    c.weighty = 1; 
    c.fill = GridBagConstraints.HORIZONTAL; 
    BufferedImage img = null; 
    try { 
     img = ImageIO.read(this.getClass().getResource("/res/add.png")); 
    } catch (IOException ex) { } 
    JButton addButton = new JButton(); 
    addButton.setIcon(new ImageIcon(img)); 
    addButton.addActionListener(this); 
    this.add(addButton, c); 
    repaint(); 

    } 
} 

不要覺得有義務調試這段代碼,只是在某些情況下我在哪裏。

+0

代替'setSize',你可以1-使用佈局管理器; 2-覆蓋'doLayout' ...你也沒有調用'super.setSize' – MadProgrammer

+0

在自定義JPanel中使用佈局管理器? – ceptno

+0

我與你的代碼有問題,你的網格窗格有沒有首選的大小 – MadProgrammer

回答

3
  • 組件應至少爲父佈局管理器提供首選大小,以確定如何最好地佈置它。您不應該對您的尺寸進行計算以期滿足這些要求......
  • 繪畫時,組件的圖形上下文已經開始轉換爲組件的x/y位置。這意味着組件的頂部/左側角落實際上是0x0
  • 您應該致電super.paintComponent。這是非常重要的,因爲它準備用於繪製的圖形上下文,這與透明組件

打交道時更加重要enter image description here

public class GridPanel extends JPanel implements MouseMotionListener, MouseListener { 

    private Rectangle offdutyRect, sbRect, driveRect, onRect; 
    private int delta = 60; 
    private int[][] gridArray; 
    int draggedStartX = -1; 
    int draggedStartY = -1; 
    private int dutyStatusSpacing = 60; 
    private int totalSpacing = 100; 

    public GridPanel() { 
     setBackground(Color.WHITE); 
     //this.setSize(new Dimension(800, 100)); 
     this.addMouseMotionListener((MouseMotionListener) this); 
     this.addMouseListener(this); 
     int gridArrayColumns = 24 * 60/delta; 
     gridArray = new int[4][gridArrayColumns]; 

     int r = 0; 
     int rHeight = this.getHeight()/4; 
     offdutyRect = new Rectangle(dutyStatusSpacing, r * rHeight, this.getWidth() - totalSpacing, rHeight); 
     r++; 
     sbRect = new Rectangle(dutyStatusSpacing, r * rHeight, this.getWidth() - totalSpacing, rHeight); 
     r++; 
     driveRect = new Rectangle(dutyStatusSpacing, r * rHeight, this.getWidth() - totalSpacing, rHeight); 
     r++; 
     onRect = new Rectangle(dutyStatusSpacing, r * rHeight, this.getWidth() - totalSpacing, rHeight); 

     Rectangle rect = null; 
     for (r = 0; r < gridArray.length; r++) { 
      if (r == 0) { 
       rect = offdutyRect; 
      } else if (r == 1) { 
       rect = sbRect; 
      } else if (r == 2) { 
       rect = driveRect; 
      } else if (r == 3) { 
       rect = onRect; 
      } 

      //I haven't actually derived any of these things, just my best guesses. 
      int len = gridArray[r].length; 
      int width = (int) (rect.getWidth()/len); 
      rect.setSize((int) (width * len), (int) rect.getHeight()); 
     } 
    } 

    public void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     //the center black bar for duty status "placeholders" 
     g.setColor(Color.black); 
     g.drawRect(0, 0, getWidth() - 1, getHeight() - 1); 
     g.drawRect((int) offdutyRect.getX(), (int) offdutyRect.getY() + (int) offdutyRect.getHeight()/2, (int) offdutyRect.getWidth(), 1); 
     g.drawRect((int) sbRect.getX(), (int) sbRect.getY() + (int) sbRect.getHeight()/2, (int) sbRect.getWidth(), 1); 
     g.drawRect((int) driveRect.getX(), (int) driveRect.getY() + (int) driveRect.getHeight()/2, (int) driveRect.getWidth(), 1); 
     g.drawRect((int) onRect.getX(), (int) onRect.getY() + (int) onRect.getHeight()/2, (int) onRect.getWidth(), 1); 
     g.setColor(Color.pink); 
     g.drawRect((int) offdutyRect.getX(), (int) offdutyRect.getY(), (int) offdutyRect.getWidth(), (int) offdutyRect.getHeight()); 
     g.drawRect((int) sbRect.getX(), (int) sbRect.getY(), (int) sbRect.getWidth(), (int) sbRect.getHeight()); 
     g.drawRect((int) driveRect.getX(), (int) driveRect.getY(), (int) driveRect.getWidth(), (int) driveRect.getHeight()); 
     g.drawRect((int) onRect.getX(), (int) onRect.getY(), (int) onRect.getWidth(), (int) onRect.getHeight()); 

     //draw the array 
     g.setColor(Color.green); 
     Rectangle rect = null; 
     for (int r = 0; r < gridArray.length; r++) { 
      if (r == 0) { 
       rect = offdutyRect; 
      } else if (r == 1) { 
       rect = sbRect; 
      } else if (r == 2) { 
       rect = driveRect; 
      } else if (r == 3) { 
       rect = onRect; 
      } 

      //I haven't actually derived any of these things, just my best guesses. 
      int len = gridArray[r].length; 
      int width = (int) (rect.getWidth()/len); 

      int height = (int) rect.getHeight() - 2; 
      for (int c = 0; c < gridArray[r].length; c++) { 
       if (gridArray[r][c] == 1) { 
        int x = (int) (rect.getX() + width * c); 
        int y = (int) rect.getY() + 2; 
        g.fillRect(x, y, width, height); 
       } 
      } 
     } 
    } 

    //implement setSize 
    //  public void setSize(Dimension d) { 
    @Override 
    public void doLayout() { 

     if (gridArray == null) { 

      int gridArrayColumns = 24 * 60/delta; 
      gridArray = new int[4][gridArrayColumns]; 
     } 
     int r = 0; 
     int rHeight = this.getHeight()/4; 
     offdutyRect = new Rectangle(dutyStatusSpacing, r * rHeight, (int) getWidth() - totalSpacing, rHeight); 
     r++; 
     sbRect = new Rectangle(dutyStatusSpacing, r * rHeight, (int) getWidth() - totalSpacing, rHeight); 
     r++; 
     driveRect = new Rectangle(dutyStatusSpacing, r * rHeight, (int) getWidth() - totalSpacing, rHeight); 
     r++; 
     onRect = new Rectangle(dutyStatusSpacing, r * rHeight, (int) getWidth() - totalSpacing, rHeight); 

     Rectangle rect = null; 
     for (r = 0; r < gridArray.length; r++) { 
      if (r == 0) { 
       rect = offdutyRect; 
      } else if (r == 1) { 
       rect = sbRect; 
      } else if (r == 2) { 
       rect = driveRect; 
      } else if (r == 3) { 
       rect = onRect; 
      } 

      //I haven't actually derived any of these things, just my best guesses. 
      int len = gridArray[r].length; 
      int width = (int) (rect.getWidth()/len); 
      rect.setSize((int) (width * len), (int) rect.getHeight()); 
     } 
    } 

    @Override 
    public Dimension getPreferredSize() { 
     return new Dimension(200, 200); 
    } 

    @Override 
    public void mouseDragged(MouseEvent e) { 
    } 

    @Override 
    public void mouseMoved(MouseEvent e) { 
    } 

    @Override 
    public void mouseClicked(MouseEvent e) { 
    } 

    @Override 
    public void mousePressed(MouseEvent e) { 
    } 

    @Override 
    public void mouseReleased(MouseEvent e) { 
    } 

    @Override 
    public void mouseEntered(MouseEvent e) { 
    } 

    @Override 
    public void mouseExited(MouseEvent e) { 
    } 
} 

我強烈建議你看看Performing Custom Painting

+0

這不會立即按下添加按鈕後顯示,調整窗口大小時之後。這是什麼原因造成的,我該如何解決? – ceptno

+0

在你的'actionPerformed'方法,調用'revalidate'在方法的結束導致佈局管理器重新佈局有分量 – MadProgrammer

5

我試圖代碼如下的佈局管理器的自定義JPanel中包含的JPanel

的組件並不關心面板將其添加到,所以也沒有在意什麼佈局管理器父面板使用。

自定義組件重寫getPreferredSize(),getMinimumSize()和getMaximumSize()方法,以便父容器的佈局管理器可以使用這些建議來確定組件的實際大小。

然後在您的paintComponent()方法中使用getWidth()和geHeight()方法來確定組件的實際大小。然後你相​​應地繪製你的組件。您的邏輯需要確定如何根據最終尺寸繪製組件。

g.clearRect(this.getX(), this.getY(), this.getWidth(), this.getHeight()); 

你的繪圖代碼應該使用(0,0)爲X/Y位置,因爲你正試圖清除面板的整個區域。 getX()/ getY()值可能不爲零,因爲父容器的佈局管理器將確定面板的位置。

+0

(super.paintComponent方法();)) – MadProgrammer

+0

+1重複的一切,我從OP的最後一個問題說... – MadProgrammer