1

我正在尝试创建一个 JPanel,它有 3 个组件排列成一行。它应该有一个彩色框、一个标签和一个删除按钮。

我将 JPanel 设置为 GridLayout,其中存储了用于彩色框的 JPanel、用于标签的 JLabel 和带有自定义 ImageIcon 的 JButton。

问题是彩色框和标签之间有一个空白区域。我已经突出显示了每个组件的边界,并且似乎没有任何组件被过度拉伸。

这是我的意思的屏幕截图:

在此处输入图像描述

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

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);

    }
}

这是标签颜色框:

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);
    }


}
4

2 回答 2

4
  1. 不要调用 setSize/setPreferredSize/setMaximumSize/setMinimumSize/setBounds/setLocation,使用适当的LayoutManager,这就是工作。
  2. 不要在paintComponent 中调用这些方法。paintComponent() = 绘制组件,因此您应该只执行绘制操作(drawLine、drawRect、...)。
  3. GridLayout 通常不是一个非常灵活的布局,因为它基于最大的首选尺寸以相同的尺寸布置所有子组件。因此,在这种简单的情况下,看看 BorderLayout、GridBagLayout,甚至是 BoxLayout 和 FlowLayout。如果您可以使用第三方库,那么 MigLayout 就是您的朋友。
于 2012-10-11T21:03:14.763 回答
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? 它只会在组件的左上角绘制一个正方形......并不是很有用,而是使用getWidthandgetHeight作为您需要影响的区域的基础。您还需要考虑组件Insets以确保您的内容被绘制在可用的视觉范围内。

这也意味着您可以更改组件的大小而无需重写整个代码部分:P

至于你的程序。使用更灵活的布局管理器。 GridLayout创建一个统一的网格来布局其组件...

在此处输入图像描述

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);
            }
        }
    }
}
于 2012-10-11T22:04:14.427 回答