我正在尝试创建一个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);
}
}
这里是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);
}
}
答案 0 :(得分:4)
答案 1 :(得分: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);
}
这样做会导致重新绘制请求被发送到重新绘制管理器,最终会调用你的paintComponent
,这会触发重新绘制请求...并告诉你的CPU再循环到100 %,你的程序没有响应。
您应该尽可能避免调用setPreferred/Minimum/MaximumSize
。让各个组件解决问题。如果您正在自定义组件,请覆盖这些方法,这将阻止某些方式开发人员更改您下方组件的大小。
你应该避免使用绝对值,特别是在绘画时。
g.fillRect(0, 0, 40, 40);
这非常危险。如果此组件添加到BorderLayout
怎么办?它只会在组件的左上角绘制一个正方形......不是很有用,而是使用getWidth
和getHeight
作为您需要实现的区域的基础。您还需要考虑组件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);
}
}
}
}