jpanel之间不需要的空间

时间:2012-10-11 20:52:28

标签: java swing jpanel

我正在尝试创建一个JPanel,其中有3个组件排成一行。它应该有一个彩色框,一个标签,然后是一个删除按钮。

我有一个JPanel设置为GridLayout,它存储彩色框的JPanel,标签的JLabel和带有自定义ImageIcon的JButton。

问题是彩色框和标签之间有空白。我突出了每个组件的边框,没有任何组件似乎过度拉伸。

以下是我的意思截图:

enter image description here

以下是我正在使用的代码: 标签类:

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 个答案:

答案 0 :(得分:4)

  1. 不要调用setSize / setPreferredSize / setMaximumSize / setMinimumSize / setBounds / setLocation,使用适当的LayoutManager,即工作。
  2. 不要在paintComponent中调用这些方法。 paintComponent()=绘制组件,因此您应该只执行绘制操作(drawLine,drawRect,...)。
  3. GridLayout通常不是一个非常灵活的布局,因为它根据最大的首选大小布局所有具有相同大小的子组件。所以在这种简单的情况下看看BorderLayout,GridBagLayout,甚至是BoxLayout和FlowLayout。如果你可以使用第三方库,那么MigLayout就是你的朋友。

答案 1 :(得分:2)

正如Guillaume指出的那样,您的代码存在一些严重问题。

不要在任何paintXxx方法

中对任何UI组件进行任何更改
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);
}

这样做会导致重新绘制请求被发送到重新绘制管理器,最终会调用你的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);
            }
        }
    }
}