Перетаскивание jlabel вокруг экрана

Итак, я пытаюсь щелкнуть и перетащить JLabel вокруг JFrame. Следующий код позволяет перемещать JLabel вокруг экрана, когда мышь нажата/перетащена в любую точку экрана, но я не уверен, как добавить второй ActionListener, чтобы проверить, щелкнула ли мышь на ярлыке, предполагая, что является решением.

Я хотел бы иметь несколько JLabels на экране, чтобы только перемещаемая метка была той, которую щелкнула мышь и теперь перетаскивается.

Спасибо.

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);
}
}

Ответ 1

Другой способ сделать это - добавить JLabel в JLayeredPane или в JPanel, удерживаемый JLayeredPane, и добавить MouseAdapter в качестве JLayeredPane MouseListener и MouseMotionListener. Затем, щелкнув на ярлыке, переместите его в JLayeredPane JLayeredPane.DRAG_LAYER, чтобы он перемещался поверх всего остального, затем поместите JLabel в зависимости от того, какой из них наиболее подходящий для мыши. Я нашел, что это хорошо работает при перемещении шахматных фигур на шахматной доске, например, и вы хотите убедиться, что кусок, который вы двигаете, отображается над всеми остальными частями при перетаскивании.

Дополнение: вы, вероятно, покинули этот поток, но если вы вернетесь или для других, я хотел бы уточнить, что я имел в виду, используя 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();
            }
        });
    }
}

Пожалуйста, не стесняйтесь публиковать любые вопросы, разъяснения или исправления.

Ответ 2

Добавить прослушиватель мыши на метку вместо панели. (Вам может понадобиться прослушиватель мыши на панели для перетаскивания, но, по крайней мере, тот, который на этикетке может сказать вам, был ли он выбран).

Ответ 3

Вдохновленный вашим кодом и ответом пользователя compilex, следует демонстрация:

Screenshot

Полный код:

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 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);
    }
}

Пояснения добавляются как комментарии.

Подсказки:

Посмотрите documentation on Container.findComponentAt(int x, int y), если вы собираетесь добавить Component в Container dragP, отличный от "перетаскиваемых" меток.

Кроме того, вы можете вместо этого использовать Container.getComponentAt(int x, int y), в этом случае. Я предлагаю вам сначала прочитать их (маленькую) документацию.

Ответ 4

Создайте две глобальные переменные:

int x_pressed = 0;
int y_pressed = 0;

затем создайте два события (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);
    }
});