【问题标题】:Drag and move a picture inside a JLabel with mouseclick使用鼠标单击在 JLabel 中拖动和移动图片
【发布时间】:2012-10-29 21:57:35
【问题描述】:

我在 JLabel 中有一个图像。

JLabel label = new JLabel(new ImageIcon("C:\\image.jpg"));
label.setSize(300,300);

我想要以下功能。

-我单击 JLabel 内的一个位置(在图像上)。

-按下鼠标按钮,我可以更改图像在 JLabel 中的位置。 (我把图片拖到JLabel里面的不同位置)

嗯,这意味着在许多情况下,图片将被裁剪并且不在视野范围内。

请告诉我如何实现这个功能?

要添加到我的 JLabel 的正确事件侦听器是什么?

【问题讨论】:

  • 您很可能需要创建一个扩展 JLabel 的类。
  • 为什么需要JLabel
  • Robin,你建议我用什么来实现这个功能? JLabel 是在考虑图像时首先想到的,但我真的是图像的菜鸟。
  • 你需要添加一个 MouseListener。正如 Code-Guru 所说,您还需要创建一个扩展 JLabel 并覆盖paintComponent 的类。在paintComponent 中,您需要在mousePressed 上删除部分图像。我正在处理这个问题,我会尽快发布答案。
  • 你也应该看看 MouseMoationListeners。

标签: java image swing drag jlabel


【解决方案1】:

这是一个基本的例子......

它的工作原理是将标签分成 3x3 网格,其中每个单元格代表图标的可能位置。

public class TestMouseDrag {

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

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

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new DragMyIcon());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    protected class DragMyIcon extends JPanel {

        private JLabel label;

        public DragMyIcon() {

            ImageIcon icon = null;

            try {
                icon = new ImageIcon(ImageIO.read(getClass().getResource("/bomb.png")));
            } catch (IOException ex) {
                ex.printStackTrace();
            }

            label = new JLabel(icon);
            label.setHorizontalAlignment(JLabel.CENTER);
            label.setVerticalAlignment(JLabel.CENTER);

            setLayout(new BorderLayout());
            add(label);

            MouseHandler handler = new MouseHandler();
            label.addMouseListener(handler);
            label.addMouseMotionListener(handler);

        }

    }

    protected class MouseHandler extends MouseAdapter {

        private boolean active = false;

        @Override
        public void mousePressed(MouseEvent e) {

            JLabel label = (JLabel) e.getComponent();
            Point point = e.getPoint();

            active = getIconCell(label).contains(point);
            if (active) {
                label.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
            } else {
                label.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
            }

        }

        @Override
        public void mouseReleased(MouseEvent e) {
            active = false;
            JLabel label = (JLabel) e.getComponent();
            label.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
        }

        @Override
        public void mouseDragged(MouseEvent e) {
            if (active) {
                JLabel label = (JLabel) e.getComponent();
                Point point = e.getPoint();

                int verticalAlign = label.getVerticalAlignment();
                int horizontalAlign = label.getHorizontalAlignment();

                if (isWithInColumn(label, point, 0)) {
                    horizontalAlign = JLabel.LEFT;
                } else if (isWithInColumn(label, point, 1)) {
                    horizontalAlign = JLabel.CENTER;
                } else if (isWithInColumn(label, point, 2)) {
                    horizontalAlign = JLabel.RIGHT;
                }

                if (isWithInRow(label, point, 0)) {
                    verticalAlign = JLabel.TOP;
                } else if (isWithInRow(label, point, 1)) {
                    verticalAlign = JLabel.CENTER;
                } else if (isWithInRow(label, point, 2)) {
                    verticalAlign = JLabel.BOTTOM;
                }

                label.setVerticalAlignment(verticalAlign);
                label.setHorizontalAlignment(horizontalAlign);

                label.invalidate();
                label.repaint();

            }
        }

        @Override
        public void mouseMoved(MouseEvent e) {
        }

        protected boolean isWithInColumn(JLabel label, Point p, int gridx) {
            int cellWidth = label.getWidth() / 3;
            int cellHeight = label.getHeight();

            Rectangle bounds = new Rectangle(gridx * cellWidth, 0, cellWidth, cellHeight);

            return bounds.contains(p);
        }

        protected boolean isWithInRow(JLabel label, Point p, int gridY) {
            int cellWidth = label.getWidth();
            int cellHeight = label.getHeight() / 3;

            Rectangle bounds = new Rectangle(0, cellHeight * gridY, cellWidth, cellHeight);

            return bounds.contains(p);
        }

        private Rectangle getIconCell(JLabel label) {

            Rectangle bounds = new Rectangle();

            int cellWidth = label.getWidth() / 3;
            int cellHeight = label.getHeight() / 3;

            bounds.width = cellWidth;
            bounds.height = cellHeight;

            if (label.getHorizontalAlignment() == JLabel.LEFT) {
                bounds.x = 0;
            } else if (label.getHorizontalAlignment() == JLabel.CENTER) {
                bounds.x = cellWidth;
            } else if (label.getHorizontalAlignment() == JLabel.RIGHT) {
                bounds.x = cellWidth * 2;
            } else {
                bounds.x = 0;
                bounds.width = 0;
            }
            //if (label.getHorizontalAlignment() == JLabel.TOP) {
            //    bounds.y = 0;
            //} else if (label.getHorizontalAlignment() == JLabel.CENTER) {
            //    bounds.y = cellHeight;
            //} else if (label.getHorizontalAlignment() == JLabel.BOTTOM) {
            //    bounds.y = cellHeight * 2;
            //} else {
            //    bounds.y = 0;
            //    bounds.height = 0;
            //}
            if (label.getVerticalAlignment() == JLabel.TOP) {
                bounds.y = 0;
            } else if (label.getVerticalAlignment() == JLabel.CENTER) {
                bounds.y = cellHeight;
            } else if (label.getVerticalAlignment() == JLabel.BOTTOM) {
                bounds.y = cellHeight * 2;
            } else {
                bounds.y = 0;
                bounds.height = 0;
            }

            return bounds;

        }

    }

}

根据反馈更新

此示例基本上使用JLayerdPane 来允许在其容器内重新定位JLabels...

public class MoveMe {

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

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

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new MoveMePane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class MoveMePane extends JLayeredPane {

        public MoveMePane() {
            int width = 400;
            int height = 400;
            for (int index = 0; index < 10; index++) {
                String text = "Label " + index;
                JLabel label = new JLabel(text);
                label.setSize(label.getPreferredSize());

                int x = (int) Math.round(Math.random() * width);
                int y = (int) Math.round(Math.random() * height);
                if (x + label.getWidth() > width) {
                    x = width - label.getWidth();
                }
                if (y + label.getHeight() > width) {
                    y = width - label.getHeight();
                }
                label.setLocation(x, y);
                add(label);
            }

            MoveMeMouseHandler handler = new MoveMeMouseHandler();
            addMouseListener(handler);
            addMouseMotionListener(handler);
        }

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

    public class MoveMeMouseHandler extends MouseAdapter {

        private int xOffset;
        private int yOffset;
        private JLabel draggy;
        private String oldText;

        @Override
        public void mouseReleased(MouseEvent me) {
            if (draggy != null) {
                draggy.setText(oldText);
                draggy.setSize(draggy.getPreferredSize());
                draggy = null;
            }
        }

        public void mousePressed(MouseEvent me) {
            JComponent comp = (JComponent) me.getComponent();
            Component child = comp.findComponentAt(me.getPoint());
            if (child instanceof JLabel) {
                xOffset = me.getX() - child.getX();
                yOffset = me.getY() - child.getY();

                draggy = (JLabel) child;
                oldText = draggy.getText();
                draggy.setText("What a drag");
                draggy.setSize(draggy.getPreferredSize());
            }
        }

        public void mouseDragged(MouseEvent me) {
            if (draggy != null) {
                draggy.setLocation(me.getX() - xOffset, me.getY() - yOffset);
            }
        }
    }
}

【讨论】:

  • 这是一个非常有用的例子。你知道为什么它只适用于第一次拖放吗?嗯,我会查看代码,看看它是否是一个快速修复。谢谢你的真棒例子。我会尝试使其适应我的程序的需要,看看它是如何进行的:)
  • @user1784129 可能是因为我已经 3 天没睡觉了 :P - 我已经修复了这个错误,它应该可以工作......更好;)
  • 我稍微修改了你的代码,让它完全按预期工作。您的代码向我展示了要添加的侦听器以及如何进行拖动。感谢您的帮助。
【解决方案2】:

首先,我建议使用布局而不是 setLayout(null) 和 setBounds()。其次,将 ImageIcon 与 JLabel 分开。最后,将 JLabel 和 ImageIcon 设置为字段而不是局部变量。

您需要添加一个 MouseListener 和一个 MouseMotionListener。

label.addMouseMotionListener(new MouseAdapter()
{
    public void mouseMoved(MouseEvent arg0)
    {
        if(clicked)
        {
            label.x++
            label.y++
            label.repaint();
        }
    }
});

label.addMouseListener(new MouseAdapter()
{
    public void mousePressed(MouseEvent arg0)
    {
        clicked = !clicked;
    }
});

(抱歉之前啰嗦了)

这会导致标签的图像出现在标签所在的位置,当您将鼠标悬停在它上面时,它会沿对角线向东南方向移动。我创建了一个新的标签类,在其中覆盖了paintComponent 并在其中添加了一个绘制图像图标方法,其中x 和y 是变量。这个想法是计算标签上的中心点,然后如果从该点向西移动图像的 x 位置 (x--),如果向南移动 (y--),则向南移动,等等。这只会将您的图像移动到标签内。如果您的鼠标在标签之外,则移动将停止。如果图像的某些部分在标签之外,则不会显示该部分。我会覆盖标签类中的绘画组件并将图像移到上方,然后为每个移动设置图标。

public class Label1 extends JLabel
{
    public int x;
    public int y;
    ImageIcon imageIcon = new ImageIcon("path");

    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
//No setLocation(x, y) method exists for an image icon or an image. You are on your own on this
        imageIcon.setLocation(x, y);
        label.setIcon(imageIcon);
    }
}

【讨论】:

  • 我要测试一下。感谢您花时间写这篇文章。我将处理图像图标的 setLocation(),看看是否找到解决方法。一会儿回来。
  • 好吧...也许我应该将 JLabel 放在 JPanel 中,然后在 JPanel 中移动它?我将尝试对此进行编码,看看它是否有效。感谢这些想法。
【解决方案3】:

这个修改后的例子是基于 MadProgrammer 的代码。

它显示了我在原始帖子中描述的行为。感谢大家的宝贵帮助,尤其是 MadProgrammer 和 Coupon22。试试看。

import java.awt.*;
import javax.swing.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseAdapter;

public class TestMouseDrag {

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

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

            JFrame frame = new JFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLayout(new BorderLayout());
            frame.add(new DragMyIcon("C://image.jpg"));
            frame.pack();
            frame.setSize(500,500);
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    });
}

protected class DragMyIcon extends JPanel {

    public static final long serialVersionUID = 172L;
    private JLabel label;

    public DragMyIcon(String path) {
        setLayout(null);

        ImageIcon icon = null;

        icon = new ImageIcon(path);

        label = new JLabel(icon);
        label.setBounds(0,0,icon.getIconWidth(), icon.getIconHeight());
        setBounds(0,0,icon.getIconWidth(), icon.getIconHeight());
        label.setHorizontalAlignment(JLabel.CENTER);
        label.setVerticalAlignment(JLabel.CENTER);

        add(label);

        MouseHandler handler = new MouseHandler();
        label.addMouseListener(handler);
        label.addMouseMotionListener(handler);

    }

}

protected class MouseHandler extends MouseAdapter {

    private boolean active = false;
    private int xDisp;
    private int yDisp;

    @Override
    public void mousePressed(MouseEvent e) {
        active = true;
        JLabel label = (JLabel) e.getComponent();

        xDisp = e.getPoint().x - label.getLocation().x;
        yDisp = e.getPoint().y - label.getLocation().y;

        label.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        active = false;
        JLabel label = (JLabel) e.getComponent();
        label.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        if (active) {
            JLabel label = (JLabel) e.getComponent();
            Point point = e.getPoint();
            label.setLocation(point.x - xDisp, point.y - yDisp);
            label.invalidate();
            label.repaint();

        }
    }

    @Override
    public void mouseMoved(MouseEvent e) {
    }
}

}

【讨论】:

  • 我建议你使用 JLayredPane 而不是使用空布局
  • 我只是挑剔,但这不是你的问题;)你要求一种在标签上下文中拖动图标的方法,而不是拖动标签它自己,那会更容易开始;P
  • 确实如此。我想这只是假装展示功能。另外,空布局是否存在固有问题?
  • null 布局通常不被鼓励,因为它们会导致无穷无尽的问题并增加程序的复杂程度(通常没有任何好处)。您可以查看DragLayout,它旨在简化此过程。不要误会我的意思,有时null 布局可能很有用,但您应该在确定之前探索所有可用的选项 - 恕我直言
  • 您是否有过修改,以使图像可以在没有空布局的情况下拖动?拖动必须是精确的,而不是网格上的正方形,除非您将网格做得如此之小以至于它更像点?快到了:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多