【发布时间】:2020-07-05 12:46:16
【问题描述】:
我在使用绝对布局将组件动态添加到 JPanel 时遇到问题(实际上不是添加,而是保存先前添加的组件)。 我可以在框架上的 jpanel 中插入一个自定义圆形按钮,但在显示之前添加的对象时遇到问题。
大约 20 年前,我编写了一个应用程序来测试最短路径和类似算法。它看起来像这样:我将标记节点添加到面板,然后使用标记线连接它们。然后我计算了路径。 我已经好几年没用过 Swing 了。现在我想在 Swing 中重复同样的任务。当然,我没有旧应用程序的副本。 一开始我遇到了一个问题:动态地将自定义组件添加到面板中。面板具有绝对布局。用户必须从菜单中选择“新节点”选项。 然后出现一个对话框——应用程序要求输入新节点的名称。输入名称后,单击鼠标时会将节点添加到某个位置。但是我有一个问题,因为我不能显示之前添加的按钮——只显示新的。我试图将旧按钮及其坐标作为一个元组存储在一个列表中——我做错了。
这似乎很简单:Core Java 书(MouseTest 第 10 章第 1 卷)中显示了一个类似的应用程序,唯一的区别是作者绘制了一个包含通过鼠标单击创建的几何形状的组件,但我想绘制我的自定义按钮(准确地说是两种组件:自定义按钮和表示带有连接按钮的距离标签的线的组件)。每个对象都必须是一个单独的组件。 请帮我解决我的问题。
public class RoutingGame extends JFrame {
private Set<String> labelNames;
private JMenuBar menuBar;
private JMenu fileMenu;
public RoutingGame() {
super();
labelNames = new HashSet<>();
setBounds(300, 200, 800, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel npanel = new JPanel();
getContentPane().add(npanel, BorderLayout.NORTH);
npanel.setLayout(new FlowLayout(FlowLayout.LEADING));
JPanel cpanel = new JPanel();
getContentPane().add(cpanel, BorderLayout.CENTER);
cpanel.setLayout(null);
menuBar = new JMenuBar();
fileMenu = new JMenu("File");
JMenuItem nodeItem = new JMenuItem("New node");
menuBar.add(fileMenu);
fileMenu.add(nodeItem);
setJMenuBar(menuBar);
nodeItem.addActionListener(e -> {
String s = "";
while (s.isBlank()) {
s = (String) JOptionPane.showInputDialog(
this,
"Choose a name for your new node:",
"Add node",
JOptionPane.PLAIN_MESSAGE,
null,
null,
"Node");
}
final String[] nodeName = {s};
setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
cpanel.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
RoundButton roundButton = new RoundButton(nodeName[0]);
Insets insets = cpanel.getInsets();
Dimension size = roundButton.getPreferredSize();
roundButton.setBounds ( insets.left + e.getX() - size.width / 2, insets.top + e.getY() - size.height / 2, size.width , size.height );
setCursor(Cursor.getDefaultCursor());
cpanel.add( roundButton );
cpanel.revalidate();
cpanel.repaint();
cpanel.removeMouseListener(this);
}
});
});
}
}
public class RoundButton extends JButton {
private static final int DEFAULT_WIDTH = 66;
private static final int DEFAULT_HEIGHT = 66;
private Shape shape;
public RoundButton(String label) {
super(label);
setContentAreaFilled(false);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT);
}
protected void paintComponent(Graphics g) {
int diameter = Math.min(getWidth(), getHeight());
int radius = diameter / 2;
if (! getModel().isArmed()) {
g.setColor(WHITE);
} else {
g.setColor( new Color(230, 230, 230) );
}
g.fillOval(getWidth() / 2 - radius, getHeight() / 2 - radius, diameter, diameter);
g.drawOval(getWidth() / 2 - radius, getHeight() / 2 - radius, diameter, diameter);
super.paintComponent(g);
}
protected void paintBorder(Graphics g) {
int diameter = Math.min(getWidth(), getHeight());
int radius = diameter / 2;
g.setColor(getForeground() );
g.drawOval(getWidth() / 2 - radius, getHeight() / 2 - radius, diameter - 1, diameter - 1);
}
}
public class RoutingGameRunner {
public static void main(String[] args) {
EventQueue.invokeLater( () -> {
try {
RoutingGame window = new RoutingGame();
window.setResizable(false);
window.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
【问题讨论】:
-
在提问时发布正确的minimal reproducible example。您的问题是关于显示组件。因此,首先让您的代码使用标准的 JDK JButton。一旦成功,您就可以使用自定义 JButton 进行测试。限制一次测试的自定义代码。简化逻辑将更容易找到问题。
标签: java swing dynamic jbutton add