java 在屏幕上拖动 jlabel

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4893265/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 08:31:07  来源:igfitidea点击:

dragging a jlabel around the screen

javaswingjlabel

提问by jjj

So I am trying to click and drag a JLabel around a JFrame. The following code allows a JLabel to be moved around the screen when the mouse is pressed / dragged at any point on the screen, but I am not sure how to add a second ActionListener to check if the mouse is clicking on the label, assuming that is the solution.

所以我试图在 JFrame 周围单击并拖动 JLabel。下面的代码允许在屏幕上的任何点按下/拖动鼠标时在屏幕上移动 JLabel,但我不确定如何添加第二个 ActionListener 来检查鼠标是否在点击标签,假设是解决方案。

I would like to have multiple JLabels on the screen so that the only label being moved is the one that the mouse has clicked and is now dragging.

我想在屏幕上有多个 JLabel,以便唯一移动的标签是鼠标单击并拖动的标签。

Thanks.

谢谢。

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

@SuppressWarnings("serial")
public class test extends JFrame implements MouseMotionListener {

private JPanel panel = new JPanel(null);    
private JLabel dragLabel = new JLabel("drag test");
private int mouseX = 200;
private int mouseY = 200;

public test() {
    this.add(panel);
    panel.setBackground(Color.WHITE);
    panel.add(dragLabel);
    dragLabel.setForeground(Color.RED);
    dragLabel.setBounds(mouseX, mouseY, 100, 50);
    panel.addMouseMotionListener(this);
}

@Override
public void mouseDragged(MouseEvent e) {
    mouseX = e.getX();
    mouseY = e.getY();
    dragLabel.setBounds(mouseX, mouseY, 100, 50);
}

@Override
public void mouseMoved(MouseEvent e) {}

public static void main(String[] args) {
    test frame = new test();
    frame.setVisible(true);
    frame.setSize(600, 400);
    frame.setResizable(false);
    frame.setLocationRelativeTo(null);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}

回答by Hovercraft Full Of Eels

Another way to do this is to add the JLabel to a JLayeredPane or to a JPanel held by a JLayeredPane and add a MouseAdapter as the JLayeredPane's MouseListener and MouseMotionListener. Then when clicking on the label, move it to the JLayeredPane's JLayeredPane.DRAG_LAYER so it moves on top of everything else, then place the JLabel on whichever is the most appropriate level on mouse release. I've found this to work well when moving chess pieces on a chess board, for instance, and you want to make sure that the piece you're moving is displayed above all the other pieces when dragging.

另一种方法是将 JLabel 添加到 JLayeredPane 或 JLayeredPane 持有的 JPanel,并添加 MouseAdapter 作为 JLayeredPane 的 MouseListener 和 MouseMotionListener。然后在单击标签时,将其移动到 JLayeredPane 的 JLayeredPane.DRAG_LAYER 使其移动到其他所有内容的顶部,然后将 JLabel 放在最适合释放鼠标的级别。例如,我发现这在棋盘上移动棋子时效果很好,并且您希望确保在拖动时移动的棋子显示在所有其他棋子之上。

Addition: You've probably left this thread, but if you come back, or for the benefit of others, I wanted to clarify what I meant by using a JLayeredPane by posting an example.

补充:您可能已经离开了这个线程,但是如果您回来或为了他人的利益,我想通过发布示例来阐明使用 JLayeredPane 的含义。

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

public class DragLabelOnLayeredPane extends JLayeredPane {
    public static final int WIDTH = 680;
    public static final int HEIGHT = 480;
    private static final int GRID_ROWS = 8;
    private static final int GRID_COLS = 6;
    private static final int GAP = 3;
    private static final Dimension LAYERED_PANE_SIZE = new Dimension(WIDTH, HEIGHT);
    private static final Dimension LABEL_SIZE = new Dimension(60, 40);
    private GridLayout gridlayout = new GridLayout(GRID_ROWS, GRID_COLS, GAP, GAP);
    private JPanel backingPanel = new JPanel(gridlayout);
    private JPanel[][] panelGrid = new JPanel[GRID_ROWS][GRID_COLS];
    private JLabel redLabel = new JLabel("Red", SwingConstants.CENTER);
    private JLabel blueLabel = new JLabel("Blue", SwingConstants.CENTER);

    public DragLabelOnLayeredPane() {
        backingPanel.setSize(LAYERED_PANE_SIZE);
        backingPanel.setLocation(2 * GAP, 2 * GAP);
        backingPanel.setBackground(Color.black);
        for (int row = 0; row < GRID_ROWS; row++) {
            for (int col = 0; col < GRID_COLS; col++) {
                panelGrid[row][col] = new JPanel(new GridBagLayout());
                backingPanel.add(panelGrid[row][col]);
            }
        }

        redLabel.setOpaque(true);
        redLabel.setBackground(Color.red.brighter().brighter());
        redLabel.setPreferredSize(LABEL_SIZE);
        panelGrid[4][3].add(redLabel);

        blueLabel.setOpaque(true);
        blueLabel.setBackground(Color.blue.brighter().brighter());
        blueLabel.setPreferredSize(LABEL_SIZE);
        panelGrid[1][1].add(blueLabel);

        backingPanel.setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
        setPreferredSize(LAYERED_PANE_SIZE);
        add(backingPanel, JLayeredPane.DEFAULT_LAYER);
        MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
        addMouseListener(myMouseAdapter);
        addMouseMotionListener(myMouseAdapter);
    }

    private class MyMouseAdapter extends MouseAdapter {
        private JLabel dragLabel = null;
        private int dragLabelWidthDiv2;
        private int dragLabelHeightDiv2;
        private JPanel clickedPanel = null;

        @Override
        public void mousePressed(MouseEvent me) {
            clickedPanel = (JPanel) backingPanel.getComponentAt(me.getPoint());
            Component[] components = clickedPanel.getComponents();
            if (components.length == 0) {
                return;
            }
            // if we click on jpanel that holds a jlabel
            if (components[0] instanceof JLabel) {

                // remove label from panel
                dragLabel = (JLabel) components[0];
                clickedPanel.remove(dragLabel);
                clickedPanel.revalidate();
                clickedPanel.repaint();

                dragLabelWidthDiv2 = dragLabel.getWidth() / 2;
                dragLabelHeightDiv2 = dragLabel.getHeight() / 2;

                int x = me.getPoint().x - dragLabelWidthDiv2;
                int y = me.getPoint().y - dragLabelHeightDiv2;
                dragLabel.setLocation(x, y);
                add(dragLabel, JLayeredPane.DRAG_LAYER);
                repaint();
            }
        }

        @Override
        public void mouseDragged(MouseEvent me) {
            if (dragLabel == null) {
                return;
            }
            int x = me.getPoint().x - dragLabelWidthDiv2;
            int y = me.getPoint().y - dragLabelHeightDiv2;
            dragLabel.setLocation(x, y);
            repaint();
        }

        @Override
        public void mouseReleased(MouseEvent me) {
            if (dragLabel == null) {
                return;
            }
            remove(dragLabel); // remove dragLabel for drag layer of JLayeredPane
            JPanel droppedPanel = (JPanel) backingPanel.getComponentAt(me.getPoint());
            if (droppedPanel == null) {
                // if off the grid, return label to home
                clickedPanel.add(dragLabel);
                clickedPanel.revalidate();
            } else {
                int r = -1;
                int c = -1;
                searchPanelGrid: for (int row = 0; row < panelGrid.length; row++) {
                    for (int col = 0; col < panelGrid[row].length; col++) {
                        if (panelGrid[row][col] == droppedPanel) {
                            r = row;
                            c = col;
                            break searchPanelGrid;
                        }
                    }
                }

                if (r == -1 || c == -1) {
                    // if off the grid, return label to home
                    clickedPanel.add(dragLabel);
                    clickedPanel.revalidate();
                } else {
                    droppedPanel.add(dragLabel);
                    droppedPanel.revalidate();
                }
            }

            repaint();
            dragLabel = null;
        }
    }

    private static void createAndShowUI() {
        JFrame frame = new JFrame("DragLabelOnLayeredPane");
        frame.getContentPane().add(new DragLabelOnLayeredPane());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                createAndShowUI();
            }
        });
    }
}

Please feel free to post any questions, need for clarification, or corrections.

请随时发布任何问题,需要澄清或更正。

回答by gthanop

Inspired by your code and user compilex's answer, follows demonstration:

受您的代码和用户 compilex 的回答的启发,请遵循以下演示:

Screenshot

截屏

Full code:

完整代码:

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;

/**
 * A demonstration of moving around labels in a panel.
 * <p>
 * Some labels show up layed out in a grid. Then the
 * user can drag any label anywhere on the panel.
 * </p>
 */
public class LabelDragger {
    public static void main(final String[] args) {
        final int labelRows = 5,    //How many rows of labels.
                  labelColumns = 5, //How many columns of labels.
                  labelWidth = 55,  //Width for each label.
                  labelHeight = 20; //Height for each label.

        //Border colors for labels:
        final Color[] colors = new Color[]{Color.BLUE, Color.GREEN, Color.BLACK, Color.GRAY};
        final Random prng = new Random(); //For selecting border color for each label.

        final JPanel dragP = new JPanel(null); //Nicely set to null! :D Did not know that trick.

        //Creating the listener for the panel:
        final MouseAdapter ma = new MouseAdapter() {
            private JLabel selectedLabel = null; //Clicked label.
            private Point selectedLabelLocation = null; //Location of label in panel when it was clicked.
            private Point panelClickPoint = null; //Panel's click point.

            //Selection of label occurs upon pressing on the panel:
            @Override
            public void mousePressed(final MouseEvent e) {

                //Find which label is at the press point:
                final Component pressedComp = dragP.findComponentAt(e.getX(), e.getY());

                //If a label is pressed, store it as selected:
                if (pressedComp != null && pressedComp instanceof JLabel) {
                    selectedLabel = (JLabel) pressedComp;
                    selectedLabelLocation = selectedLabel.getLocation();
                    panelClickPoint = e.getPoint();
                    //Added the following 2 lines in order to make selectedLabel
                    //paint over all others while it is pressed and dragged:
                    dragP.setComponentZOrder(selectedLabel, 0);
                    selectedLabel.repaint();
                }
                else {
                    selectedLabel = null;
                    selectedLabelLocation = null;
                    panelClickPoint = null;
                }
            }

            //Moving of selected label occurs upon dragging in the panel:
            @Override
            public void mouseDragged(final MouseEvent e) {
                if (selectedLabel != null
                        && selectedLabelLocation != null
                        && panelClickPoint != null) {

                    final Point newPanelClickPoint = e.getPoint();

                    //The new location is the press-location plus the length of the drag for each axis:
                    final int newX = selectedLabelLocation.x + (newPanelClickPoint.x - panelClickPoint.x),
                              newY = selectedLabelLocation.y + (newPanelClickPoint.y - panelClickPoint.y);

                    selectedLabel.setLocation(newX, newY);
                }
            }
        };
        dragP.addMouseMotionListener(ma); //For mouseDragged().
        dragP.addMouseListener(ma); //For mousePressed().

        //Filling the panel with labels:
        for (int row = 0; row < labelRows; ++row)
            for (int col = 0; col < labelColumns; ++col) {

                //Create label for (row, col):
                final JLabel lbl = new JLabel("Label" + (row * labelColumns + col));
                lbl.setHorizontalAlignment(JLabel.CENTER);
                //lbl.setVerticalAlignment(JLabel.CENTER);
                lbl.setBounds(col * labelWidth, row * labelHeight, labelWidth, labelHeight); //Grid-like positioning.
                lbl.setBorder(new LineBorder(colors[prng.nextInt(colors.length)], 2)); //Set a border for clarity.

                //Add label to panel:
                dragP.add(lbl);
            }

        //Creating and showing the main frame:
        final JFrame frame = new JFrame(LabelDragger.class.getSimpleName());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //The size of the content pane adds some extra room for moving the labels:
        final Dimension paneSize = new Dimension((int)(1.5 * labelWidth * labelColumns),
                                                 (int)(1.5 * labelHeight * labelRows));
        frame.getContentPane().setPreferredSize(paneSize);
        frame.getContentPane().add(dragP);

        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

Explanations are added as comments.

解释作为注释添加。

Tips:

小贴士

Take a look at the documentation on Container.findComponentAt(int x, int y), if you are going to add Components on the dragPContainer, other than "draggable" labels.

看看documentation on Container.findComponentAt(int x, int y), 如果您要在 上添加Components dragPContainer,而不是“可拖动”标签。

Also, you can instead use Container.getComponentAt(int x, int y), in this case. I suggest you read their (small) documentation first.

此外,Container.getComponentAt(int x, int y)在这种情况下,您可以改为使用, 。我建议您先阅读他们的(小)文档。

回答by jzd

Add a mouse listener to the label instead of the panel. (You might still need a mouse listener on the panel for the dragging but at least the one on the label can tell you if it was selected).

将鼠标侦听器添加到标签而不是面板。(您可能仍然需要面板上的鼠标侦听器进行拖动,但至少标签上的侦听器可以告诉您它是否被选中)。

回答by compilex

Create two global variables:

创建两个全局变量:

int x_pressed = 0;
int y_pressed = 0;

then create two events (mousePressed and mouseDragged over JLabel):

然后创建两个事件(mousePressed 和 mouseDragged over JLabel):

lbl_banner.addMouseListener(new MouseAdapter()
{
    @Override
    public void mousePressed(MouseEvent e) {
        //catching the current values for x,y coordinates on screen
        x_pressed = e.getX();
        y_pressed = e.getY();
    }
});

lbl_banner.addMouseMotionListener(new MouseMotionAdapter(){
    @Override
    public void mouseDragged(MouseEvent e){
        //and when the Jlabel is dragged
        setLocation(e.getXOnScreen() - x_pressed, e.getYOnScreen() - y_pressed);
    }
});