如何通过鼠标光标在Java GUI中拖动图像?

4

//我的代码从一个目录中调用n个图像,将它们放在JPanel上

 public void imageAdder(int n, String name){
    BufferedImage myPic = null;
    for (int i = 0; i <= n; i++){
        try {
        myPic = ImageIO.read(new File("Images/" + name + i + ".jpg"));
        } catch (Exception e){
        System.out.println("no file man cmon");
        }
        JLabel picLabel = new JLabel(new ImageIcon(myPic));
      //  picLabel.setBounds(mouseX, mouseY, 100, 50);
      //  picLabel.addMouseMotionListener(this);
      //  picLabel.addMouseListener(this);
        canvas.add(picLabel);
    }}

我了解到DragSource类有一个可以拖动类型为image的方法,但是我不确定是否适用于我的代码。如果我想使用鼠标自由拖动图像,应该怎么做?

2个回答

7
有许多方法可以实现这一点......例如,您可以使用自定义绘画来自己绘制每个图像。每次按下/拖动鼠标时,您需要计算被拖动的是哪个图像。
一个稍微简单的解决方案可能是使用JLayeredPane并继续使用JLabel来呈现图像,然后您可以使用MouseListenerMouseMoitionListener来检测何时按下和/或拖动标签,并相应地更新其位置...
有关更多详细信息,请参见如何编写鼠标侦听器如何使用分层窗格

Drag

import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestDrag {

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

    public TestDrag() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JLayeredPane {

        public TestPane() {
            File[] images = new File("C:\\hold\\thumbnails").listFiles(new FileFilter() {
                @Override
                public boolean accept(File pathname) {
                    String name = pathname.getName().toLowerCase();
                    return name.endsWith(".png") || 
                                    name.endsWith(".jpg") || 
                                    name.endsWith(".bmp") ||
                                    name.endsWith(".gif");
                }
            });

            int x = 0;
            int y = 0;
            for (File imgFile : images) {

                try {
                    BufferedImage img = ImageIO.read(imgFile);
                    JLabel label = new JLabel(new ImageIcon(img));
                    label.setSize(label.getPreferredSize());
                    label.setLocation(x, y);
                    MouseHandler mh  = new MouseHandler();
                    label.addMouseListener(mh);
                    label.addMouseMotionListener(mh);
                    add(label);
                    x += 20;
                    y += 20;
                } catch (IOException exp) {
                    exp.printStackTrace();
                }

            }

        }

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

        public class MouseHandler extends MouseAdapter {

            private Point offset;

            @Override
            public void mousePressed(MouseEvent e) {
                JLabel label = (JLabel) e.getComponent();
                moveToFront(label);
                offset = e.getPoint();
            }

            @Override
            public void mouseDragged(MouseEvent e) {
                int x = e.getPoint().x - offset.x;
                int y = e.getPoint().y - offset.y;
                Component component = e.getComponent();
                Point location = component.getLocation();
                location.x += x;
                location.y += y;
                component.setLocation(location);
            }

        }

    }

}

嘿,谢谢你的回复!我对Java和面向对象语言还很陌生,所以我想花几天时间来理解你写的代码,并看看它是否可以应用到我的游戏中。我会尽快告诉你进展如何,非常感谢你的帮助!我很感激。 - Marlo Vin
这只是我能想到的最快、最简单的方法,希望能有所帮助。 - MadProgrammer
嘿,这可能是一个愚蠢的问题,但每个类应该在单独的文件中对吧?你排列括号的方式让我觉得它们应该在同一个文件中,因为class testdrag是代码中的最后一个括号。但是我被告知每个类都应该有自己的文件。请尽快告诉我。 - Marlo Vin
这是一个自包含的示例,因此它可以驻留在单个类中,但不必如此,因为我正在使用事件源,MouseHandler 不需要包含在 TestPane 中。这些被称为内部类。 - MadProgrammer
你的代码运行得非常好!非常感谢!我想问一下,如果我想把这些类分别放在同一个目录下的不同文件中,会有什么问题吗?我试过了,但它无法识别“moveToFront”方法。你知道为什么会出现这种情况吗?因为movetofront是内置的,所以导入应该不是问题(我已经考虑到了)。 - Marlo Vin
抱歉回复晚了。moveToFront是JLayeredPane的一个方法,为了让鼠标监听器调用它,它需要一个引用。你可以直接通过构造函数传递引用,或者使用被点击的组件并使用它的getParent方法,这种情况下,它将返回一个JLayerdPane(你需要将结果容器转换为JLayerdPane)。 - MadProgrammer

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接