【问题标题】:JLabel mouse events for Drag and Drop用于拖放的 JLabel 鼠标事件
【发布时间】:2011-03-15 08:30:09
【问题描述】:

我想通过在 JLabel 上覆盖鼠标事件来启用拖放功能,但是当我在 mousePressed 事件中定义拖放时,mouseReleased 不会对该 JLabel 生效。我是不是做错了什么?

            Thumbnails[I_Loop].setText("1");
            Thumbnails[I_Loop].setTransferHandler(new TransferHandler("text"));
            Thumbnails[I_Loop].addMouseListener( new MouseAdapter() {
                public void  mouseReleased(MouseEvent me) {
                       System.out.println("here mouse released");
                  }
                public void mousePressed(MouseEvent me) {
                    System.out.println("here mouse pressed");
                    JComponent comp = (JComponent) me.getSource();
                    TransferHandler handler = comp.getTransferHandler();
                    handler.exportAsDrag(comp, me, TransferHandler.COPY);
            });

*Thumbnails 是 JLabel 的数组

运行程序时,拖放可以工作,但不会打印“此处鼠标已释放”的语句。但是,当我从 mousePressed() 方法中删除负责 DND 的代码时,会打印“此处鼠标已释放”。

这段代码有什么问题?

【问题讨论】:

  • “对同一个 JLabel 不生效”是什么意思?
  • 我的意思是当我在 JLabel 上释放鼠标时没有发生任何事情,“这里鼠标释放”的语句没有打印
  • 如果没有编译和运行的最小代码,很难看出哪里出了问题。您能否提供一个 SSCCE 代码,以便我们自己测试和查看?见sscce.org

标签: java swing


【解决方案1】:

@Thomas 是正确的,但有两个替代方案值得注意:

  • 这个example 展示了如何使用JLayeredPane 拖动组件;这个variation 扩展了这个概念;这个最近的example 使用了类似的方法。

  • 下面的代码展示了如何使用MouseMotionListener;这个更复杂的example 使用相同的原理。

代码:

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JFrame;
import javax.swing.JPanel;

/** @see https://stackoverflow.com/a/5312702/230513 */
public class MouseDragTest extends JPanel {

    private static final String TITLE = "Drag me!";
    private static final int W = 640;
    private static final int H = 480;
    private Point textPt = new Point(W / 2, H / 2);
    private Point mousePt;

    public MouseDragTest() {
        this.setFont(new Font("Serif", Font.ITALIC + Font.BOLD, 32));
        this.addMouseListener(new MouseAdapter() {

            @Override
            public void mousePressed(MouseEvent e) {
                mousePt = e.getPoint();
                repaint();
            }
        });
        this.addMouseMotionListener(new MouseMotionAdapter() {

            @Override
            public void mouseDragged(MouseEvent e) {
                int dx = e.getX() - mousePt.x;
                int dy = e.getY() - mousePt.y;
                textPt.setLocation(textPt.x + dx, textPt.y + dy);
                mousePt = e.getPoint();
                repaint();
            }
        });
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(W, H);
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        int w2 = g.getFontMetrics().stringWidth(TITLE) / 2;
        g.drawString(TITLE, textPt.x - w2, textPt.y);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                JFrame f = new JFrame(TITLE);
                f.add(new MouseDragTest());
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.pack();
                f.setLocationRelativeTo(null);
                f.setVisible(true);
            }
        });
    }
}

【讨论】:

  • 你说得对,我在一些程序中也使用了第二种方法。
  • +1,很好的例子来展示如何将自定义绘画与真实组件相对。
【解决方案2】:

好吧,如果我没记错的话,拖放机制会捕获所有鼠标事件并自行处理它们。因此,不再抛出正常的 MouseEvents。您需要在 JLabel 的 DropTarget 上注册 DropTargetListener。

【讨论】:

    【解决方案3】:

    它必须是 JLabel 吗?我用一个字符串创建了一个类,可能会让你开始..

    import java.awt.Graphics;
    import java.awt.MouseInfo;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseListener;
    
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    
    
    public class mainProgram extends JPanel implements Runnable
    {
        private static final long serialVersionUID = 1L;
        public static boolean MOUSE_DOWN = false;
        public static String str;
    
        public mainProgram() 
        {
            JFrame win = new JFrame("Window");
    
            win.add(this);
    
            win.setSize(700,500);
            win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            win.setVisible(true);
            str = "Drag me!";
            new Thread(this).start();
        }
    
        public void paintComponent(Graphics g)
        {
            super.paintComponent(g);
    
            if(MOUSE_DOWN)
            {
                g.drawString(str, MouseInfo.getPointerInfo().getLocation().x, MouseInfo.getPointerInfo().getLocation().y);
            }
        }
    
        @Override
        public void run() 
        {
            Thread t = Thread.currentThread();
    
            this.addMouseListener(new MouseListener()
            {
    
                @Override
                public void mouseClicked(MouseEvent arg0) 
                {
    
                }
    
                @Override
                public void mouseEntered(MouseEvent arg0) 
                {
    
                }
    
                @Override
                public void mouseExited(MouseEvent arg0) 
                {
    
                }
    
                @Override
                public void mousePressed(MouseEvent arg0) 
                {
                    MOUSE_DOWN = true;
                }
    
                @Override
                public void mouseReleased(MouseEvent arg0) 
                {
                    MOUSE_DOWN = false;
                }
    
            });
    
            while(t==Thread.currentThread())
            {
                if(MOUSE_DOWN)
                    repaint();
    
                try {Thread.sleep(10);}
                catch (InterruptedException e) {e.printStackTrace();}
            }   
        }
    }
    

    【讨论】:

    • 我试了你的课,它做的很漂亮,我在拖动时需要情感,但我处理的 JLabel 里面包含图像
    • 这种做法值得一提,但在实现上存在很大问题。一般来说,它没有正确使用线程,尤其是事件调度线程。我提出了一个替代方案。
    • 很好地改进了我的代码。我们仍然有一个问题,它应该只在鼠标悬停在文本上时鼠标开始拖动时才做出反应。
    • FontMetrics getStringBounds() 方法返回适合在mousePressed() 中使用的Rectangle2D。引用的example 显示了一种多选方法。顺便说一句,您需要使用@trashgod 让我看到对您的答案的评论。
    猜你喜欢
    • 2020-05-10
    • 2011-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多