How to click and drag something without it deselecting

浪尽此生 提交于 2019-12-02 12:24:09

One of the side effects of a drag operation is the fact that mouseClicked won't be called. Why is this important? Basically you can use this fact to make a decision about whether a object should be deselected or not within the mouseClicked event instead of something like mousePressed or mouseReleased.

It does require you to maintain some information about the current and previous states, so you know whether the object was just selected or was previously selected, but the basic idea works well.

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class WhatADrag {

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

    public WhatADrag() {
        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 JPanel {

        private List<Rectangle> boxes;
        private Rectangle selected;

        public TestPane() {
            boxes = new ArrayList<>(25);
            int x = 0;
            int y = 0;
            for (int index = 0; index < 10; index++) {
                boxes.add(new Rectangle(x, y, 100, 100));
                x += 25;
                y += 25;
            }

            MouseAdapter ma = new MouseAdapter() {

                private Rectangle previous;
                private Point delta;

                @Override
                public void mousePressed(MouseEvent e) {
                    List<Rectangle> reversed = new ArrayList<>(boxes);
                    Collections.reverse(reversed);
                    previous = selected;
                    if (selected == null || !selected.contains(e.getPoint())) {
                        for (Rectangle box : reversed) {
                            if (box.contains(e.getPoint())) {
                                selected = box;
                                delta = new Point(e.getX() - selected.x, e.getY() - selected.y);
                                repaint();
                                break;
                            }
                        }
                        if (selected != null) {
                            boxes.remove(selected);
                            boxes.add(boxes.size() - 1, selected);
                        }
                    } else if (selected != null) {
                        delta = new Point(e.getX() - selected.x, e.getY() - selected.y);
                    }
                }

                @Override
                public void mouseClicked(MouseEvent e) {
                    if (selected == previous && selected != null && selected.contains(e.getPoint())) {
                        selected = null;
                        repaint();
                    }
                }

                @Override
                public void mouseDragged(MouseEvent e) {
                    if (selected != null) {
                        int x = e.getX() - delta.x;
                        int y = e.getY() - delta.y;
                        selected.x = x;
                        selected.y = y;
                        repaint();
                    }
                }

            };

            addMouseListener(ma);
            addMouseMotionListener(ma);
        }

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

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            for (Rectangle box : boxes) {
                if (box != selected) {
                    g2d.setColor(Color.BLUE);
                    g2d.fill(box);
                    g2d.setColor(Color.BLACK);
                    g2d.draw(box);
                }
            }
            if (selected != null) {
                g2d.setColor(Color.CYAN);
                g2d.fill(selected);
                g2d.setColor(Color.BLUE);
                g2d.draw(selected);
            }
            g2d.dispose();
        }

    }

}

I am just so lost. I am looking at all this code and don't even understand what it is doing.

Yeah, I feel like this about my code a lot.

Basically...

First: mousePressed is called, I reverse my list of objects, because the top most component will be the last in the list (this is my requirement), I store the currently selected object in the previous variable, I use this to determine if there has been a change in selection or not. I check to see if the user clicked the selected object or not, if they did, we can basically skip every thing else. If not, we determine what they clicked, if anything. The delta is simply the difference between the place they clicked and the location of the object, this is used to make the drag more natural

If no drag occurs: mouseClicked is called. We test to see if the selected object is equal to the previous object and if the mouse was clicked within the selected object, if these are true, then the currently selected object should be deselected. Otherwise the user has basically just changed the selection, so we don't want to immediately deselect it.

Else if a drag occurs: mouseDragged is called. We simply check to see if something is selected, we calculate the difference between the current mouse position and the "click offset" and update the position of the selected object

Clear as mud :P

One thing to also remember is mouseReleased will always be called after mousePressed, even if mouseClicked isn't (which is called after mouseReleased when no dragging occurs).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!