перетаскивая метку по экрану - PullRequest
8 голосов
/ 04 февраля 2011

Итак, я пытаюсь нажать и перетащить 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);
}
}

Ответы [ 4 ]

20 голосов
/ 04 февраля 2011

Другой способ сделать это - добавить JLabel в JLayeredPane или в JPanel, удерживаемую JLayeredPane, и добавить MouseAdapter в качестве MouseListener и MouseMotionListener JLayeredPane. Затем, нажимая на метку, переместите ее в JLayeredPane.DRAG_LAYER JLayeredPane, чтобы она двигалась поверх всего остального, затем поместите 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();
            }
        });
    }
}

Пожалуйста, не стесняйтесь оставлять вопросы, уточнения или исправления.

3 голосов
/ 24 августа 2016

Вдохновленный вашим кодом и ответом пользователя 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'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);
    }
}

добавлены в качестве комментариев.

Советы :

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

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

3 голосов
/ 04 февраля 2011

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

1 голос
/ 08 мая 2014

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

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