【问题标题】:JLabel is not moving properly using mouse motion listener, Why?JLabel 没有使用鼠标运动监听器正确移动,为什么?
【发布时间】:2014-10-15 05:43:34
【问题描述】:

每当我拖动鼠标时,我都需要相应地移动 JLabel。
为什么它在拖动时显示多个 JLabel 而没有在适当的位置显示组件?

public class Mover extends JFrame 
{

private JPanel jPanel;
private JLabel jLabel1;
private JLabel jLabel2;
private int myXX = 0;
private int myYY = 0;

public Mover() {
    setSize(500, 500);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    jPanel = new JPanel(null);
    jLabel1 = new JLabel("label one");
    jLabel2 = new JLabel("label two");

    jLabel1.setBounds(100, 100, 100, 100);
    jLabel2.setBounds(100, 100, 100, 100);
    jLabel1.addMouseMotionListener(new MouseMotionListener() {

        @Override
        public void mouseMoved(MouseEvent e) {
        }

        @Override
        public void mouseDragged(MouseEvent e) {
            System.out.println("Label One");
            myXX = e.getX() - (jLabel1.getWidth() / 2);
            myYY = e.getY() - (jLabel1.getHeight() / 2);
            jLabel1.setLocation(myXX, myYY);
            repaint();
        }
    });
    jLabel2.addMouseMotionListener(new MouseMotionListener() {

        @Override
        public void mouseMoved(MouseEvent e) {
        }

        @Override
        public void mouseDragged(MouseEvent e) {
            System.out.println("Label Two");

            myXX = e.getX() - (jLabel2.getWidth() / 2);
            myYY = e.getY() - (jLabel2.getHeight() / 2);
            jLabel2.setLocation(myXX, myYY);
            repaint();
        }
    });
    jPanel.add(jLabel1);
    jPanel.add(jLabel2);
    add(jPanel);
    repaint();
    revalidate();
    setVisible(true);
}

public static void main(String args[]) {
    new Mover();
}
}

这个问题有什么完美的解决方案吗?
显然提前谢谢。

【问题讨论】:

  • MouseEvent 是基于生成它的本地组件上下文,即 x/y 位置相对于标签的 x/y 位置
  • 没有布局管理器时调用revalidate 没有意义,没有什么需要重新验证...
  • 哦,但是我们可以根据鼠标移动来移动标签的位置吗?
  • 是的,您需要将源点转换为它的父上下文...查看示例答案...

标签: java swing


【解决方案1】:

MouseEvent 信息与生成事件的组件(在本例中为标签)相关。

这意味着0x0 实际上是标签的左上角。您需要将事件的点信息转换为它的父上下文,例如...

Point p = e.getPoint();
p = SwingUtilities.convertPoint(e.getComponent(), p, e.getComponent().getParent());

您也不需要创建 myXXmyYY 实例字段,因为它们只真正具有驱动它们的鼠标事件的上下文。

您还应该查看Initial Threads 并确保您在事件调度线程的上下文中启动您的程序...

您也不需要为每个组件创建单独的侦听器,只需巧妙地使用来自MouseEvent 的可用信息,您就可以为所有组件使用单个侦听器并减少代码重复...

import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Mover extends JFrame {

    private JPanel jPanel;
    private JLabel jLabel1;
    private JLabel jLabel2;

    public Mover() {
        setSize(500, 500);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        jPanel = new JPanel(null);
        jLabel1 = new JLabel("label one");
        jLabel2 = new JLabel("label two");

        jLabel1.setBounds(100, 100, 100, 100);
        jLabel2.setBounds(100, 100, 100, 100);

        MouseMotionListener mover = new MouseMotionListener() {

            @Override
            public void mouseMoved(MouseEvent e) {
            }

            @Override
            public void mouseDragged(MouseEvent e) {
                System.out.println("Label One");

                Component child = e.getComponent();
                Point p = e.getPoint();
                p = SwingUtilities.convertPoint(e.getComponent(), p, e.getComponent().getParent());

                int myXX = p.x - (child.getWidth() / 2);
                int myYY = p.y - (child.getHeight() / 2);
                child.setLocation(myXX, myYY);
                repaint();
            }
        };

        jLabel1.addMouseMotionListener(mover);
        jLabel2.addMouseMotionListener(mover);

        jPanel.add(jLabel1);
        jPanel.add(jLabel2);
        add(jPanel);
        setVisible(true);
    }

    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                new Mover();
            }
        });
    }
}

如果我没有指出直接从像 JFrame 这样的顶级容器扩展是不好的做法,并且会将您锁定在一次性容器中,那么我会伤害您,从而难以重复使用将来的容器或将其添加到其他容器中...此外,您实际上并没有向它添加任何功能...

【讨论】:

  • 哇哦!但是你能告诉我 UIManager 是必须在 swing 中添加的吗?
  • 不,我只是非常讨厌金属的外观和感觉;)
  • 是的,我知道了,但它需要在 MouseEvent 中制作子组件吗?
  • 不,这比重复调用MouseEvent#getComponent....更简单。
  • +1 表示您的快速响应并被接受,因为它是真正的解决方案...... :)
猜你喜欢
  • 2017-12-17
  • 2014-05-27
  • 1970-01-01
  • 2017-02-17
  • 2018-03-09
  • 1970-01-01
  • 2015-11-30
  • 2015-10-19
  • 2012-03-30
相关资源
最近更新 更多