如何在没有变量名的情况下访问 Swing UI 组件?

问题描述 投票:0回答:1

我想通过单击带有以下代码的按钮来创建按钮:

addButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {

            projects_panel.add(new JButton("Button"));
                revalidate();
                repaint();
            }
        });

现在我想用 TextField 更改按钮的文本,但是如何在不知道其名称的情况下访问特定的 UI 组件。 我尝试用附加到字符串的递增数字来命名按钮,但这不起作用。我还读到,Java 没有这个功能。

java swing variables
1个回答
0
投票

如何在没有变量名的情况下访问 Swing UI 组件?

    /**
     * This returns the first showing Component that matches a given name.
     *
     * @param components leave this completely empty to search ALL showing components.
     */
    public static Component findComponentByName(String name, Component... components) {
        Objects.requireNonNull(name);
        if (components.length == 0)
            components = Window.getWindows();
        for (Component c : components) {
            if (c.isShowing()) {
                if (name.equals(c.getName())) {
                    return c;
                } else if (c instanceof Container container) {
                    Component[] children = container.getComponents();
                    if (children.length > 0) {
                        Component returnValue = findComponentByName(name, children);
                        if (returnValue != null)
                            return returnValue;
                    }
                }
            }
        }
        return null;
    }

(另外:记住 JComponent 的 name 和它的 text 不同。请参阅

JComponent.setName(String)
JButton.setText(String)

但是这种方法仍然让你离目标还很远:

现在我想用 TextField 更改按钮的文本

这里有一些潜在的入门代码:

package com.pump.winnow;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Objects;

/**
 * This panel has an "Add Project" button. Every time you click it a new JButton is created. When it is first
 * created: a JTextField sits on top of the JButton to let you edit the button's name. You can also enter this
 * special editing mode by right-clicking the JButton.
 */
public class ProjectPanel extends JPanel {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame f = new JFrame();
                f.getContentPane().add(new ProjectPanel());
                f.pack();
                f.setVisible(true);
            }
        });
    }

    /**
     * This positions a JTextField over a button. It assumes the button will only ever have one child (the JTextField),
     * or no children.
     */
    static class ButtonTextEditorLayout implements LayoutManager {
        private final JButton button;
        private final Dimension prefSize, minSize;

        public ButtonTextEditorLayout(JButton button) {
            this.button = button;
            prefSize = button.getUI().getPreferredSize(button);
            minSize = button.getUI().getMinimumSize(button);
        }

        @Override
        public void addLayoutComponent(String name, Component comp) {}

        @Override
        public void removeLayoutComponent(Component comp) {}

        @Override
        public Dimension preferredLayoutSize(Container parent) {
            if (button != parent) throw new IllegalArgumentException();
            if (button.getComponentCount() == 0)
                return button.getUI().getPreferredSize(button);
            return prefSize;
        }

        @Override
        public Dimension minimumLayoutSize(Container parent) {
            if (button != parent) throw new IllegalArgumentException();
            if (button.getComponentCount() == 0)
                return button.getUI().getMinimumSize(button);
            return minSize;
        }

        @Override
        public void layoutContainer(Container parent) {
            if (button != parent) throw new IllegalArgumentException();
            if (button.getComponentCount() == 1) {
                JTextField field = (JTextField) button.getComponent(0);
                Insets buttonInsets = button.getInsets();
                Insets fieldInsets = field.getInsets();
                field.setBounds(new Rectangle(buttonInsets.left - fieldInsets.left,
                        buttonInsets.top - fieldInsets.top,
                        button.getWidth() - buttonInsets.left - buttonInsets.right + fieldInsets.left + fieldInsets.right,
                        button.getHeight() - buttonInsets.top - buttonInsets.bottom + fieldInsets.top + fieldInsets.bottom));
            }
        }
    }


    JPanel toolbar = new JPanel();
    JButton addButton = new JButton("Add Project");

    JPanel content = new JPanel(new FlowLayout());
    public ProjectPanel() {
        toolbar.setBackground(Color.gray);
        setLayout(new BorderLayout());
        add(toolbar, BorderLayout.NORTH);
        add(content, BorderLayout.CENTER);

        toolbar.setLayout(new FlowLayout());
        toolbar.add(addButton);

        addButton.addActionListener(e -> {
            String projectName = "Project #" + (content.getComponentCount() + 1);
            JButton projectButton = new JButton(projectName);
            content.add(projectButton);
            setupButtonTextEditor(projectButton);
            revalidate();

            projectButton.addMouseListener(new MouseAdapter() {

                // IIRC different platforms use different mouse events as popup triggers
                @Override
                public void mousePressed(MouseEvent e) {
                    if (e.isPopupTrigger())
                        setupButtonTextEditor(projectButton);
                }

                @Override
                public void mouseReleased(MouseEvent e) {
                    if (e.isPopupTrigger())
                        setupButtonTextEditor(projectButton);
                }
            });
        });

        setPreferredSize(new Dimension(400, 400));
    }

    private void setupButtonTextEditor(JButton button) {
        JTextField field = new JTextField(button.getText());
        field.setBorder(null);
        field.setFont(button.getFont());
        field.addActionListener(e -> {
            removeTextField(button, field);
        });
        field.addFocusListener(new FocusAdapter() {
            @Override
            public void focusLost(FocusEvent e) {
                removeTextField(button, field);
            }
        });
        button.setLayout(new ButtonTextEditorLayout(button));
        button.add(field);

        field.selectAll();
        field.requestFocus();

        button.revalidate();
    }

    private void removeTextField(JButton button, JTextField field) {
        if (field.getParent() == button) {
            button.remove(field);
            button.setText(field.getText());
            button.repaint();
        }
    }
}

我需要模型或更多描述来了解如何更好地实现您的目标。我可能(?)倾向于为每个项目创建一个自定义 JPanel,并在该面板中嵌入一个永久的 JTextField。

© www.soinside.com 2019 - 2024. All rights reserved.