2012-10-11 172 views
1

我想創建一個JPanel,它有3個組件排成一行。它應該有一個彩色框,一個標籤,然後是一個刪除按鈕。jpanels之間不需要的空間

我有一個JPanel設置爲GridLayout,它存儲彩色框的Janel,標籤的JLabel和帶有自定義ImageIcon的JButton。

問題是彩色方塊和標籤之間有空白。我突出了每個組件的邊界,沒有任何組件似乎被過度延伸。

這裏是我的意思截圖:

enter image description here

這裏是我一起工作的代碼: Label類:

public class Label extends JPanel { 

    JButton btnDeleteObject; 
    // Delete icon 
    ImageIcon delIcon = new ImageIcon("Delete.png"); 
    Image img = delIcon.getImage(); 
    Image newimg = img.getScaledInstance(28, 28, java.awt.Image.SCALE_SMOOTH); 
    ImageIcon scaledDelIcon = new ImageIcon(newimg); 

    Color labelColour; 

    public Label(String labelName, Color labelColour) { 
     this.labelColour = labelColour; 

     setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); 

     addComponents(labelName); 

    } 

    private void addComponents(String labelName) { 

     JPanel innerContainer = new JPanel(new GridLayout(1, 3)); 
     JLabel name = new JLabel(labelName); 

     LabelColourBox cBox = new LabelColourBox(); 

     name.setMaximumSize(new Dimension(80, 40)); 
     name.setPreferredSize(new Dimension(80, 40)); 
     name.setSize(new Dimension(80, 40)); 

     name.setBorder(BorderFactory.createLineBorder(Color.blue)); 

     setBorder(BorderFactory.createLineBorder(Color.black)); 

//  name.setBorder(new EmptyBorder(5, 5, 5, 5)); 

     // Add action to delete button for Icon 
     Action action = new AbstractAction("Button Label", scaledDelIcon) { 
      // This method is called when the button is pressed 
      public void actionPerformed(ActionEvent evt) { 
       System.out.println("delete"); 
      } 
     }; 

     btnDeleteObject = new JButton(action); 

     // Remove label, background 
     btnDeleteObject.setText(""); 
     btnDeleteObject.setContentAreaFilled(false); 

     setAlignmentX(LEFT_ALIGNMENT); 

     innerContainer.add(cBox); 
     innerContainer.add(name); 
     innerContainer.add(btnDeleteObject); 

     add(innerContainer); 

    } 
} 

這裏是LabelColourBox:

public class LabelColourBox extends JPanel{ 

    public LabelColourBox() { 
     setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); 
    } 


    @Override 
    protected void paintComponent(Graphics g) { 

     super.paintComponent(g); 
     setBorder(BorderFactory.createLineBorder(Color.green)); 

     setMaximumSize(new Dimension(40, 40)); 
     setPreferredSize(new Dimension(40, 40)); 
     setSize(new Dimension(40, 40)); 

     g.setColor(Color.RED); 
     g.fillRect(0, 0, 40, 40); 
    } 


} 

回答

2

正如Guillaume指出的那樣,您的代碼存在一些嚴重問題。

從來沒有從任何paintXxx方法

protected void paintComponent(Graphics g) { 
    super.paintComponent(g); 

    // This is INCREDIBLY bad 
    setBorder(BorderFactory.createLineBorder(Color.green)); 
    setMaximumSize(new Dimension(40, 40)); 
    setPreferredSize(new Dimension(40, 40)); 
    setSize(new Dimension(40, 40)); 
    //------------ 

    g.setColor(Color.RED); 
    g.fillRect(0, 0, 40, 40); 
} 

這樣做會導致重畫請求被髮送到重繪管理器中作出任何UI組件的任何變化,這最終會打電話給你paintComponent將觸發重繪請求...並告訴你的CPU,因爲它循環高達100%,並且你的程序變得沒有響應。

您應儘可能避免撥打setPreferred/Minimum/MaximumSize。讓各個組件完成它。如果您正在自定義組件,請覆蓋這些方法,它會阻止開發人員以某種方式更改您所在組件的大小。

您應該避免絕對值,特別是在繪畫時。

g.fillRect(0, 0, 40, 40); 

這是非常危險的。如果此組件被添加到BorderLayout會怎麼樣?它只會在組件的左上角繪製一個正方形......並不是很有用,而是使用getWidthgetHeight作爲您需要實現的區域的基礎。您還需要考慮組件Insets,以確保您的內容在可用的可視範圍內被繪製。

這也意味着你可以改變組件的大小,而無需重寫整個代碼段:P

至於你的程序。使用更靈活的佈局管理器。 GridLayout創建在佈局其組件均勻網格...

enter image description here

public class Main { 

    public static void main(String[] args) { 
     new Main(); 
    } 

    public Main() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException ex) { 
       } catch (InstantiationException ex) { 
       } catch (IllegalAccessException ex) { 
       } catch (UnsupportedLookAndFeelException ex) { 
       } 

       JFrame frame = new JFrame(); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.setLayout(new GridLayout(3, 1)); 
       frame.add(new Label("One", Color.BLACK)); 
       frame.add(new Label("Two", Color.BLACK)); 
       frame.add(new Label("Three", Color.BLACK)); 
       frame.pack(); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class Label extends JPanel { 

     JButton btnDeleteObject; 
     // Delete icon 
     ImageIcon delIcon = new ImageIcon("Delete.png"); 
     Image img = delIcon.getImage(); 
     Image newimg = img.getScaledInstance(28, 28, java.awt.Image.SCALE_SMOOTH); 
     ImageIcon scaledDelIcon = new ImageIcon(newimg); 
     Color labelColour; 

     public Label(String labelName, Color labelColour) { 
      this.labelColour = labelColour; 

//   setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); 
      // Not sure why you want to do this, but this would 
      // be a more useful layout manager in the this context 
      // Personally, I would just layout the components directly onto 
      // this container... 
      setLayout(new BorderLayout()); 

      addComponents(labelName); 

     } 

     private void addComponents(String labelName) { 

//   JPanel innerContainer = new JPanel(new GridLayout(1, 3)); 
      JPanel innerContainer = new JPanel(new GridBagLayout()); 
      JLabel name = new JLabel(labelName); 

      LabelColourBox cBox = new LabelColourBox(); 

//   name.setMaximumSize(new Dimension(80, 40)); 
//   name.setPreferredSize(new Dimension(80, 40)); 
//   name.setSize(new Dimension(80, 40)); 

      name.setBorder(BorderFactory.createLineBorder(Color.blue)); 

      setBorder(BorderFactory.createLineBorder(Color.black)); 

//  name.setBorder(new EmptyBorder(5, 5, 5, 5)); 

      // Add action to delete button for Icon 
      Action action = new AbstractAction("Button Label", scaledDelIcon) { 
       // This method is called when the button is pressed 
       public void actionPerformed(ActionEvent evt) { 
        System.out.println("delete"); 
       } 
      }; 

      btnDeleteObject = new JButton(action); 

      // Remove label, background 
      btnDeleteObject.setText(""); 
      btnDeleteObject.setContentAreaFilled(false); 

      setAlignmentX(LEFT_ALIGNMENT); 

      GridBagConstraints gbc = new GridBagConstraints(); 
      gbc.gridx = 0; 
      gbc.gridy = 0; 
      gbc.fill = GridBagConstraints.BOTH; 

      innerContainer.add(cBox, gbc); 
      gbc.gridx++; 
      gbc.weightx = 1; 
      gbc.anchor = GridBagConstraints.WEST; 
      innerContainer.add(name, gbc); 
      gbc.gridx++; 
      gbc.weightx = 0; 
      innerContainer.add(btnDeleteObject, gbc); 

      add(innerContainer); 

     } 

     public class LabelColourBox extends JPanel { 

      public LabelColourBox() { 
       setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); 
      } 

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

      @Override 
      public Dimension getMinimumSize() { 
       return getPreferredSize(); 
      } 

      @Override 
      public Dimension getMaximumSize() { 
       return getPreferredSize(); 
      } 

      @Override 
      protected void paintComponent(Graphics g) { 

       super.paintComponent(g); 

       // DON'T DO THIS, THIS IS A VERY BAD IDEA, THIS WILL RESULT 
       // IN A NEW REPAINT REQUEST BEING SENT TO THE REPAINT MANAGER 
       // CAUSE THIS METHOD TO BE CALLED AND NEW REPAINT REQUEST BEING... 
       // you get the idea.. 
       //setBorder(BorderFactory.createLineBorder(Color.green)); 
       //setMaximumSize(new Dimension(40, 40)); 
       //setPreferredSize(new Dimension(40, 40)); 
       //setSize(new Dimension(40, 40)); 

       g.setColor(Color.RED); 
       g.fillRect(0, 0, getWidth() - 1, getHeight() - 1); 
       g.setColor(Color.GREEN); 
       g.drawRect(0, 0, getWidth() - 1, getHeight() - 1); 
      } 
     } 
    } 
} 
4
  1. 不要調用setSize/setPreferredSize/setMaximumSize/setMinimumSize/setBounds/setLocation,請使用適當的LayoutManager,即有工作。
  2. 不要在paintComponent中調用這些方法。 paintComponent()=繪製組件,因此您應該只執行繪製操作(drawLine,drawRect,...)。
  3. GridLayout通常不是一個非常靈活的佈局,因爲它根據最大的首選大小來佈局所有具有相同大小的子組件。所以在這種簡單的情況下,請看一下BorderLayout,GridBagLayout,甚至是BoxLayout和FlowLayout。如果你可以使用第三方庫,MigLayout是你的朋友。