【问题标题】:Java: Adding events to dynamically created componentsJava:向动态创建的组件添加事件
【发布时间】:2018-04-30 18:13:04
【问题描述】:

我正在用 Java 构建一个 UI。我想使用按钮创建新组件,例如 JLabel。所以每次我点击一个按钮时,它都会创建一个新的 JLabel 并将它们放在一个特定的 JPanel 中。

然后,我希望能够根据用户点击标签的方式对标签做一些事情。

通过鼠标左键,我希望他们能够在屏幕上拖动标签。

点击鼠标右键我想打开一个新窗口,可以在其中输入某些数据,绑定到标签(这可能涉及动态创建变量)。

我一直在玩弄一些我在 Google 上搜索过的代码。我可以在面板中获得一个按钮来创建新标签,但是当我尝试让它们拖动时,我一次只能显示一个标签,并且在按下第二个按钮后,移动标签并不顺畅,它跳来跳去。

我什至还没有尝试实现任何鼠标右键单击的东西。如果有人能指出我正确的方向,我将不胜感激。

public class Testing {

    JFrame frame;

 //Launch the application.

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                try {
                    Testing window = new Testing();
                    window.frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
    });
}

 //Create the application.

public Testing() {
    initialize();
    }

/**
 * Initialize the contents of the frame.
 */
private void initialize() {
    JPanel area;
    JButton btnCreate;
    JLabel dragLabel;

    frame = new JFrame();
    frame.setBounds(100, 100, 511, 542);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().setLayout(null);
    frame.setVisible(true);

    area = new JPanel();
    area.setBounds(10, 11, 477, 404);
    frame.getContentPane().add(area);
    area.setLayout(new BorderLayout());

    btnCreate = new JButton("Create Label");
    dragLabel = new JLabel("Drag Me");
    btnCreate.setBounds(10, 425, 477, 67);
    frame.getContentPane().add(btnCreate);
    btnCreate.addActionListener(new ActionListener(){
        @Override
        public void actionPerformed(ActionEvent e){
            area.add(dragLabel);
            area.revalidate();


    DragListener drag = new DragListener();
    dragLabel.addMouseListener(drag);
    dragLabel.addMouseMotionListener(drag);
    }
    });

  }
}

class DragListener extends MouseInputAdapter
{
Point location;
MouseEvent pressed;

public void mousePressed(MouseEvent me) {
    pressed = me;
}

public void mouseDragged(MouseEvent me)
{
    if(SwingUtilities.isLeftMouseButton(me)){
        Component component = me.getComponent();
        location = component.getLocation(location);
        int x = location.x - pressed.getX() + me.getX();
        int y = location.y - pressed.getY() + me.getY();
        component.setLocation(x, y);
         }
     }
}

编辑 - 我相当确定主要问题在于 JLabel 本身是如何添加到面板中的。每次按下按钮时,它都会重新添加相同的标签,这会使工作变得混乱。

很遗憾,我不知道该如何处理。我做了更多的挖掘,因为动态变量是不可能的,我将不得不使用数组或映射或某种类型。有了它,我似乎可以声明组件数组。出于我的目的需要这样的东西吗?

【问题讨论】:

    标签: java events dynamic draggable


    【解决方案1】:

    您的代码中确实有一些奇怪的东西。我不想什么都做,而且我也不是任何想像力的专家,但我试图删除多余或矛盾的东西。我怀疑您所做的部分工作只是复制粘贴位而没有真正将它们放入代码中。

    无论如何,您需要在侦听器内部创建标签,以便每次单击时都会创建一个新标签。否则,您只能创建一个标签,并且每次都重复使用相同的标签。

    我在右键单击时实现了一个对话框以输入标签名称,不知道您想要做什么,但至少它会检测到右键单击。

    一般来说,使用布局管理器比对所有内容都进行硬编码更容易。在这里,您有一个边框布局,但忽略了它。

    class Main {
    
        //Launch the application.
        public static void main(String[] args) {
            DrageableLabel window = new DrageableLabel();
        }
    }
    
    public class DrageableLabel {
    
        public DrageableLabel() {
            initialize();
        }
    
        /**
         * Initialize the contents of the frame.
         */
        private void initialize() {
            JFrame frame = new JFrame();
            Container area = frame.getContentPane();
            area.setLayout(new BorderLayout());
    
            JButton btnCreate = new JButton("Create Label");
            btnCreate.addMouseListener(new MouseAdapter() {
                @Override
                public void mousePressed(MouseEvent e) {
                    if (SwingUtilities.isRightMouseButton(e)) {
                        /* 
                        This is where you create your new window
                        for now I've added a dialog that takes a string parameter and creates a label with that string
                        I moved the method code to create a new drageable label outside the actionlistener to make it less confusing and reuseable
                        Either build w-e you want directly in here
                        or call a method that does it (which I prefer)
                         */
                        String string = JOptionPane.showInputDialog(frame, "Enter your message", "Messages", JOptionPane.CANCEL_OPTION);
                        addDrageableLabel(string, area);
                    } else if (SwingUtilities.isLeftMouseButton(e)) {
                        addDrageableLabel("Drag me", area);
                    }
                }
            });
            area.add(btnCreate, BorderLayout.SOUTH);
    
            frame.setBounds(100, 100, 511, 542);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
        }
    
        // This is the method that creates and adds a drageable label
        public void addDrageableLabel(String labelName, Container container) {
            JLabel dragLabel = new JLabel(labelName);
            container.add(dragLabel, BorderLayout.CENTER);
            container.validate();
    
            DragListener drag = new DragListener();
            dragLabel.addMouseListener(drag);
            dragLabel.addMouseMotionListener(drag);
        }
    }
    
    class DragListener extends MouseInputAdapter {
    
        Point location;
        MouseEvent pressed;
    
        @Override
        public void mousePressed(MouseEvent me) {
            pressed = me;
        }
    
        @Override
        public void mouseDragged(MouseEvent me) {
            Component component = me.getComponent();
            location = component.getLocation(location);
            int x = location.x - pressed.getX() + me.getX();
            int y = location.y - pressed.getY() + me.getY();
            component.setLocation(x, y);
        }
    }
    

    【讨论】:

    • 实际上,除了 DragListener 类之外,大部分内容都是由 Eclipse 设置的。我在玩弄他们的 GUI 组件。无论如何,我感谢您的帮助。它让我进入了下一步。同样,我想做的是允许每个标签通过右键单击打开自己的窗口。该窗口将包括诸如用于输入字符串的文本框和下拉框之类的内容。例如,字符串数据将连接到标签,下拉框将更改标签背景。
    • 好的,很抱歉假设了一些事情。我用代码中的更多 cmets 更新了答案。我已经使用具有文本字段的对话框窗口来实现它,并且该文本字段用作创建标签的参数。如果你想要更多的东西,你可能不得不创建一个新的框架,里面有你想要的。
    • 新问题...每次我向 JPanel 添加一个新组件时,所有其他组件都会重置它们的位置。这显然是 Layouts 和 revalidate() 方法的问题。我该如何避免这种情况?我希望所有以前创建的标签都准确地保留在它们所在的位置,直到用户手动更改它。我想只使用空布局,但人们倾向于避免使用它。
    • validate() 可以在任何容器上调用,您可以在框架内的不同容器中使用不同的元素,并且只验证您想要的容器。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-28
    • 1970-01-01
    • 2019-05-13
    • 2019-08-10
    • 1970-01-01
    • 1970-01-01
    • 2020-03-24
    相关资源
    最近更新 更多