简体   繁体   English

java swing动态添加自定义按钮

[英]java swing dynamically adding custom button

I have a problem with adding components dynamically to JPanel with absolute layout (in fact not with adding but with saving previously added components).我在使用绝对布局将组件动态添加到 JPanel 时遇到问题(实际上不是添加而是保存以前添加的组件)。 I can insert one custom circle button into a jpanel on a frame but I have a problem with displaying objects I added before.我可以在框架上的 jpanel 中插入一个自定义圆形按钮,但在显示之前添加的对象时遇到问题。

Almost 20 years ago I wrote an application to test shortest path and similar algorithms.大约 20 年前,我编写了一个应用程序来测试最短路径和类似算法。 It looked like that: I added labeled nodes to a panel and then connected them using a labeled line.它看起来像这样:我将标记节点添加到面板,然后使用标记线将它们连接起来。 Then I calculated paths.然后我计算了路径。 I haven't used Swing from several years.我已经好几年没有使用 Swing 了。 Now I'd like to repeat the same task in Swing.现在我想在 Swing 中重复相同的任务。 Of course I have no copy of my old app.当然,我没有旧应用程序的副本。 I've got a problem on the beginning: dynamically adding custom components to a panel.一开始我遇到了一个问题:向面板动态添加自定义组件。 The panel has an absolute layout.面板具有绝对布局。 User has to choose “New node” option from menu.用户必须从菜单中选择“新节点”选项。 Then a dialog box appears – application asks for a name of the new node.然后出现一个对话框——应用程序要求输入新节点的名称。 After putting the name the node is added in a place when the mouse is clicked.输入名称后,单击鼠标时将节点添加到某个位置。 But I have a problem because I can't display buttons added earlier – only new ones are displayed.但是我有一个问题,因为我无法显示之前添加的按钮——只显示新的按钮。 I tried to store old buttons together with their coordinates as a tuple in a list – I did sth wrong.我试图将旧按钮及其坐标作为一个元组存储在列表中——我做错了。

It seemed to be easy: a similar application is shown in Core Java book (MouseTest 10th chapter 1st volume), the only difference is author draws one component containing geometrical shapes created on mouse-click but I 'd like to draw my custom buttons (precisely two kinds of components: custom buttons and a component representing a line with a distance label connecting the buttons ).这似乎很简单:Core Java 书籍(MouseTest 第 10 章第 1 卷)中显示了一个类似的应用程序,唯一的区别是作者绘制了一个包含在鼠标单击时创建的几何形状的组件,但我想绘制我的自定义按钮(正好有两种组件:自定义按钮和表示带有连接按钮的距离标签的线的组件)。 Each object has to be a separate component.每个对象都必须是一个单独的组件。 Please help me to solve my problem.请帮我解决我的问题。

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

But I have a problem because I can't display buttons added earlier但是我有一个问题,因为我无法显示之前添加的按钮

Why do you have to display the buttons again?为什么你必须再次显示按钮? If you added them to the panel they won't disappear unless you have logic to remove them.如果您将它们添加到面板中,它们不会消失,除非您有删除它们的逻辑。

In any case, have you done any debugging?无论如何,您是否进行了任何调试?

button.setBounds( xpos + mouseCoord[0]  - size.width / 2, ypos +  
    mouseCoord[1] - size.height / 2, size.width  , size.height );

Code like the above should be restructured to something like:像上面这样的代码应该被重组为:

int x = xpos + e.getX() - (size.width / 2);
int y = ypos + e.getY() - (size.height / 2);
button.setBounds(x, y, size.width, size.height);

Because now you can actually add some debug code to make sure your calculations are correct:因为现在您实际上可以添加一些调试代码来确保您的计算是正确的:

System.out.println(x + " : " + y + " : " + size);

Code like the above will verify that:像上面这样的代码将验证:

  1. you actually invoke your looping code你实际上调用了你的循环代码
  2. the bounds of the button is correct按钮的边界是正确的

I'm guessing the location is wrong and the buttons are being placed on top of one another.我猜这个位置是错误的,按钮被放置在彼此的顶部。

I'm not understanding this logic:我不明白这个逻辑:

roundButton.setBounds ( insets.left + mouseCoord[0]  - size.width / 2, insets.top + mouseCoord[1] - size.height / 2, size.width  , size.height );
buttonTuples.add( new ButtonTuple(roundButton, mouseCoord[0], mouseCoord[1]));

You add the component at once location, but then save a different location in the ButtonTuple class.您在一次位置添加组件,然后在 ButtonTuple 类中保存不同的位置。

Why do you even need the last two parameters?为什么你甚至需要最后两个参数? The bounds of the button has already been set.按钮的边界已经设置。

Edit:编辑:

In addition to all the above suggestions, the biggest problem is that you need to create a new instance of the RoundButton:除了以上所有建议之外,最大的问题是您需要创建一个 RoundButton 的新实例:

roundButton = new RoundButton();
roundButton.setBounds(…);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM