Java:向动态创建的组件添加事件

Posted

技术标签:

【中文标题】Java:向动态创建的组件添加事件【英文标题】:Java: Adding events to dynamically created components 【发布时间】: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 本身是如何添加到面板中的。每次按下按钮时,它都会重新添加相同的标签,这会使工作变得混乱。

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

【问题讨论】:

【参考方案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() 可以在任何容器上调用,您可以在框架内的不同容器中使用不同的元素,并且只验证您想要的容器。

以上是关于Java:向动态创建的组件添加事件的主要内容,如果未能解决你的问题,请参考以下文章

Angular 2:向动态创建的组件添加指令

Angular 7 - 向动态创建的组件添加拖放行为

如何在动态添加的组件上使用事件发射器?

易语言 动态创建组件 怎么给创建的组件写代码

如何创建动态的 React Native 组件

在 Vue 中动态添加带有事件的不同组件