如何设置优先级鼠标监听器

时间:2013-01-11 07:55:35

标签: java swing drag-and-drop mouseevent jlist

我有一个包含列表和按钮的面板。列表将MouseAdapter设置为mouseClick()。我已将MouseAdaptermousePressed()以及mouseReleased()MouseMotionAdapter添加到面板mouseDragged

拖放仅在单击面板时有效。

即使我点击列表,如何使拖动工作?

简单的考试:

public class DragTest extends JFrame{
private boolean drag;
private Point btnCoord;
private Point startPoint;

public DragTest(){
    setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    setSize(500,500);
    setLayout(null);
    final JPanel panel = new JPanel();
    final JButton button = new JButton();
    button.setText("Button");
    button.setSize(30,60);
    button.setLocation(50, 50);
    panel.setLayout(null);
    setContentPane(panel);
    panel.addMouseMotionListener(new MouseMotionAdapter() {
        @Override
        public void mouseDragged(MouseEvent e) {
            if (drag){
                panel.setLocation(btnCoord.x-(startPoint.x-e.getX()),btnCoord.y-(startPoint.y-e.getY()));
            }
        }
    });
    panel.addMouseListener(new MouseAdapter() {
        @Override
        public void mousePressed(MouseEvent e) {
            drag = true;
            startPoint = e.getPoint();
            btnCoord = panel.getLocation();
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            drag = false;
        }
    });
    getContentPane().add(button);
}

public static void main(String[] args) {
    JFrame frame = new DragTest();
    frame.setVisible(true);
}
}

如果拖动面板,一切正常,如果开始拖动按钮,则按钮拦截事件。

1 个答案:

答案 0 :(得分:5)

以上代码有很多错误......

  • 请勿使用null / Absolute LayoutManagerHave a look at Laying Out Components Within a Container
  • 不要在组件和setSize上致电JFrame(如果实施了正确的布局管理器,您只需添加组件并在pack()上致电JFrame
  • 在EDT上创建和操作Swing组件。详细了解Concurrency in Swing
  • 在可见容器中添加/删除组件后,您应该在容器上调用revalidate()repaint()

我一直在使用自己的小ComponentDrag API,这样我们就可以在JComponent或多个JComponent上拖动Swing组件。它绝不是没有错误的(尤其是今天完成它的多个组件部分,所以你永远不知道)

您可以创建JButton并添加到JPanel

    JButton button = new JButton("Text");

    JPanel panel1 = new JPanel() {
        @Override
        public Dimension getPreferredSize() {
            return new Dimension(300, 300);
        }
    };
    panel1.add(button);

通过传递容器的参数,即ComponentDrag / JFrameJDialog来创建JWindow类的实例,并注册可拖动的组件并调用setName("Droppable")在你的JPanel上允许拖放正确地进行,尤其是在多个JComponents等之间进行,你只能为你想要删除Swing组件的JPanel等执行此操作:

    JFrame frame=..;//has access to setGlassPane same applies for JDialog and JWindow
    frame.add(panel1);

    ComponentDrag cd=new ComponentDrag(frame);
    cd.registerComponent(button);
    panel1.setName("Droppable");//needed for the dragging and dropping to work correctly especailly over multiple components

你的好处:)。

以下是2个用于分析目的的完整示例:

1)显示移动JButton的逻辑,并使用ComponentDrag并重写其componentDropped方法重新定位:

在拖动之前:

enter image description here

4拖到1位后:

enter image description here

import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class DragButtonsTest {

    ArrayList<JButton> buttons = new ArrayList<>();

    public DragButtonsTest() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        final JPanel panel = new JPanel(new GridLayout(2, 2));

        ComponentDrag cd = new ComponentDrag(frame) {
            @Override
            protected void componentDropped(MouseEvent me) {
                HashMap<Integer, JButton> collisions = new HashMap<>();
                JButton draggedButton = (JButton) me.getSource();

                for (JButton btn : buttons) {//iterate through all buttons and get the number of collsions of each
                    if (btn != draggedButton) {//dont chck button we were dragging
                        int col = checkPerPixelCollision(draggedButton, btn);
                        System.out.println("Button " + btn.getText());
                        System.out.println(col);
                        collisions.put(col, btn);
                    }
                }

                //lets get the button which had most collisions
                int maxCollisions = 0;
                JButton intersectingButton = null;
                for (Map.Entry<Integer, JButton> entry : collisions.entrySet()) {
                    Integer collisionCount = entry.getKey();
                    JButton button = entry.getValue();
                    if (collisionCount > maxCollisions) {
                        maxCollisions = collisionCount;
                        intersectingButton = button;
                    }
                }

                boolean reLayout = false;

                if (maxCollisions > 0) {//check if there was any
                    System.out.println("Button " + draggedButton.getText() + " is intersecting more of Button " + intersectingButton.getText());
                    System.out.println("Collisions: " + maxCollisions);
                    reLayout = true;
                } else {
                    System.out.println("No change made");
                    reLayout = false;
                }

                ArrayList<JButton> tmpButtons = (ArrayList<JButton>) buttons.clone();//create clone of buttons

                if (reLayout) {//a button as moved and panel needs to be layed out
                    buttons.clear();//clear old buttons

                    for (JButton b : tmpButtons) {//re-order jbuttons
                        if (b == intersectingButton) {
                            buttons.add(draggedButton);
                        } else if (b == draggedButton) {
                            buttons.add(intersectingButton);
                        } else {
                            buttons.add(b);
                        }
                    }
                    panel.removeAll();//remove all buttons
                    for (JButton btn : buttons) {//iterate through all buttons and get the number of collsions of each
                        panel.add(btn);//re-add buttons according to arraylist
                    }
                    panel.revalidate();
                    panel.repaint();
                }
                super.componentDropped(me);

            }
        };

        for (int i = 0; i < 4; i++) {
            JButton b = new JButton(String.valueOf(i + 1));
            panel.add(b);
            buttons.add(b);
            cd.registerComponent(b);
        }

        frame.add(panel);

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

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new DragButtonsTest();
            }
        });
    }

    public HashSet<String> getMask(JButton e) {
        HashSet<String> mask = new HashSet<>();
        int pixel, a;
        BufferedImage bi = componentToImage(e); //gets the current image being shown

        for (int i = 0; i < bi.getWidth(); i++) { // for every (x,y) component in the given box, 
            for (int j = 0; j < bi.getHeight(); j++) {
                pixel = bi.getRGB(i, j); // get the RGB value of the pixel
                a = (pixel >> 24) & 0xff;
                if (a != 0) {  // if the alpha is not 0, it must be something other than transparent
                    mask.add((e.getX() + i) + "," + (e.getY() - j)); // add the absolute x and absolute y coordinates to our set
                }
            }
        }
        return mask;  //return our set
    }

    public static BufferedImage componentToImage(Component component) {
        BufferedImage img = new BufferedImage(component.getWidth(), component.getHeight(), BufferedImage.TRANSLUCENT);
        Graphics g = img.getGraphics();
        component.paintAll(g);
        return img;
    }

    // Returns true if there is a collision between object a and object b   
    public int checkPerPixelCollision(JButton b, JButton b2) {
        // This method detects to see if the images overlap at all. If they do, collision is possible
        int ax1 = (int) b2.getX();
        int ay1 = (int) b2.getY();

        int ax2 = ax1 + (int) b2.getWidth();
        int ay2 = ay1 + (int) b2.getHeight();

        int bx1 = (int) b.getX();
        int by1 = (int) b.getY();

        int bx2 = bx1 + (int) b.getWidth();

        int by2 = by1 + (int) b.getHeight();

        if (by2 < ay1 || ay2 < by1 || bx2 < ax1 || ax2 < bx1) {
            return 0; // Collision is impossible.
        } else { // Collision is possible.
            // get the masks for both images
            HashSet<String> maskPlayer1 = getMask(b2);
            HashSet<String> maskPlayer2 = getMask(b);
            maskPlayer1.retainAll(maskPlayer2);  // Check to see if any pixels in maskPlayer2 are the same as those in maskPlayer1
            if (maskPlayer1.size() > 0) {  // if so, than there exists at least one pixel that is the same in both images, thus
                return maskPlayer1.size();
            }
        }
        return 0;
    }
}

class ComponentDrag {

    private MouseAdapter ma;
    private ArrayList<JComponent> components = new ArrayList<>();
    private int startingX, startingY;
    private boolean autoLayout = true;
    private final JFrame container;
    private JPanel glassPane;
    boolean firstTime = true;
    private JComponent lastClickedContainer;

    public ComponentDrag(final JFrame container) {
        this.container = container;
        glassPane = new JPanel();
        glassPane.setOpaque(false);
        glassPane.setLayout(null);
        this.container.setGlassPane(glassPane);

        new Timer(10, new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                if (container.isVisible()) {
                    glassPane.setVisible(true);
                    ((Timer) ae.getSource()).stop();
                }
            }
        }).start();

        ma = new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent me) {
                super.mousePressed(me);
                componentPressed(me);
            }

            @Override
            public void mouseReleased(MouseEvent me) {
                super.mouseReleased(me);
                componentDropped(me);
            }

            @Override
            public void mouseDragged(MouseEvent me) {
                super.mouseDragged(me);
                componentDragged(me);
            }
        };
    }

    public JComponent findDroppableUnderGlassPane(Point p, Container container, Component source) {
        JComponent c = null;
        Component[] comps = container.getComponents();
        for (Component com : comps) {
            if (com.getName() != null) {
                if (com.getName().equals("Droppable") && com instanceof JComponent) {
                    if (com.contains(SwingUtilities.convertPoint(source, p, com))) {
                        return (JComponent) com;
                    }
                } else if (com instanceof Container) {
                    findDroppableUnderGlassPane(p, (Container) com, source);
                }
            }
        }
        return c;
    }

    public boolean isAutoLayout() {
        return autoLayout;
    }

    public void setAutoLayout(boolean autoLayout) {
        this.autoLayout = autoLayout;
    }

    protected void componentDropped(MouseEvent me) {
        firstTime = true;
        Component droppedComponent = (Component) me.getSource();
        droppedComponent.setCursor(null);

        JComponent jc = findDroppableUnderGlassPane(me.getPoint(), container.getContentPane(), (Component) me.getSource());

        if (jc != null) {
            glassPane.removeAll();
            glassPane.revalidate();
            glassPane.repaint();

            jc.add(droppedComponent);
            System.out.println("Removed from glasspane and added to: " + jc);

            if (autoLayout) {
                if (lastClickedContainer != null) {
                    lastClickedContainer.revalidate();
                    lastClickedContainer.repaint();
                }
                droppedComponent.revalidate();
                droppedComponent.repaint();
                jc.revalidate();
                jc.repaint();
            }

        } else {
            glassPane.removeAll();
            glassPane.revalidate();
            glassPane.repaint();
            if (lastClickedContainer != null) {
                lastClickedContainer.add(droppedComponent);
                lastClickedContainer.revalidate();
                lastClickedContainer.repaint();
            }
        }
    }

    protected void componentPressed(MouseEvent me) {
        JComponent jc = findDroppableUnderGlassPane(me.getPoint(), container.getContentPane(), (Component) me.getSource());

        if (jc != null && jc.getName().equals("Droppable")) {
            lastClickedContainer = jc;
            System.out.println("Pressed: " + lastClickedContainer);
        }

        boolean clickedRegisteredComponent = false;

        Component clickedComponent = (Component) me.getSource();

        for (Component component : ComponentDrag.this.components) {
            if (component.equals(clickedComponent)) {
                clickedRegisteredComponent = true;
                break;
            }
        }

        if (clickedRegisteredComponent) {
            startingX = me.getX();
            startingY = me.getY();
            clickedComponent.setCursor(new Cursor(Cursor.MOVE_CURSOR));
        }
    }

    protected void componentDragged(MouseEvent me) {
        Component draggedComponent = (Component) me.getSource();

        if (firstTime && lastClickedContainer != null) {
            firstTime = false;
            lastClickedContainer.remove(draggedComponent);
            lastClickedContainer.revalidate();
            lastClickedContainer.repaint();
            glassPane.add(draggedComponent);
            glassPane.revalidate();
            glassPane.repaint();
            System.out.println("Removed from: " + lastClickedContainer + " \nAnd added to glasspane for dragging");
        }

        //MouseEvent will refire on each drag with the position being relative to the firing Component
        draggedComponent.setLocation((me.getX() - startingX) + draggedComponent.getLocation().x, (me.getY() - startingY) + draggedComponent.getLocation().y);
    }

    void registerComponent(JComponent draggableComp) {
        draggableComp.addMouseListener(ma);
        draggableComp.addMouseMotionListener(ma);
        components.add(draggableComp);
    }

    void deregisterComponent(JComponent draggableComp) {
        draggableComp.removeMouseListener(ma);
        draggableComp.removeMouseMotionListener(ma);
        components.remove(draggableComp);
    }
}

2)简单地说明如何在JLabel s

之间拖动2 JPanel s

拖动我标签之前拖动:

enter image description here

拖动标签后:

enter image description here

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

/**
 *
 * @author David
 */
public class DragOverMultipleComponentsTest {

    public DragOverMultipleComponentsTest() {
        createAndShowUI();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new DragOverMultipleComponentsTest();
            }
        });
    }

    private void createAndShowUI() {
        final JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);


        JLabel draggableLabel = new JLabel("<- Drag me");
        JLabel draggableLabel2 = new JLabel("<- Drag me too");

        JLabel labelPanel1 = new JLabel("Drag 'em here");
        JPanel panel1 = new JPanel() {
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(300, 300);
            }
        };
        panel1.add(labelPanel1);
        panel1.setName("Droppable");

        JLabel labelPanel2 = new JLabel("Drag 'em here");
        JPanel panel2 = new JPanel();
        panel2.add(labelPanel2);
        panel2.add(draggableLabel);
        panel2.add(draggableLabel2);
        panel2.setName("Droppable");

        JSeparator js = new JSeparator(JSeparator.VERTICAL);

        ComponentDrag cd = new ComponentDrag(frame);

        cd.registerComponent(draggableLabel);
        cd.registerComponent(draggableLabel2);

        frame.add(panel1, BorderLayout.WEST);
        frame.add(js);
        frame.add(panel2, BorderLayout.EAST);

        frame.pack();
        frame.setVisible(true);
    }
}
class ComponentDrag {

    private MouseAdapter ma;
    private ArrayList<JComponent> components = new ArrayList<>();
    private int startingX, startingY;
    private boolean autoLayout = true;
    private final JFrame container;
    private JPanel glassPane;
    boolean firstTime = true;
    private JComponent lastClickedContainer;

    public ComponentDrag(final JFrame container) {
        this.container = container;
        glassPane = new JPanel();
        glassPane.setOpaque(false);
        glassPane.setLayout(null);
        this.container.setGlassPane(glassPane);

        new Timer(10, new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                if (container.isVisible()) {
                    glassPane.setVisible(true);
                    ((Timer) ae.getSource()).stop();
                }
            }
        }).start();

        ma = new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent me) {
                super.mousePressed(me);
                componentPressed(me);
            }

            @Override
            public void mouseReleased(MouseEvent me) {
                super.mouseReleased(me);
                componentDropped(me);
            }

            @Override
            public void mouseDragged(MouseEvent me) {
                super.mouseDragged(me);
                componentDragged(me);
            }
        };
    }

    public JComponent findDroppableUnderGlassPane(Point p, Container container, Component source) {
        JComponent c = null;
        Component[] comps = container.getComponents();
        for (Component com : comps) {
            if (com.getName() != null) {
                if (com.getName().equals("Droppable") && com instanceof JComponent) {
                    if (com.contains(SwingUtilities.convertPoint(source, p, com))) {
                        return (JComponent) com;
                    }
                } else if (com instanceof Container) {
                    findDroppableUnderGlassPane(p, (Container) com, source);
                }
            }
        }
        return c;
    }

    public boolean isAutoLayout() {
        return autoLayout;
    }

    public void setAutoLayout(boolean autoLayout) {
        this.autoLayout = autoLayout;
    }

    protected void componentDropped(MouseEvent me) {
        firstTime = true;
        Component droppedComponent = (Component) me.getSource();
        droppedComponent.setCursor(null);

        JComponent jc = findDroppableUnderGlassPane(me.getPoint(), container.getContentPane(), (Component) me.getSource());

        if (jc != null) {
            glassPane.removeAll();
            glassPane.revalidate();
            glassPane.repaint();

            jc.add(droppedComponent);
            System.out.println("Removed from glasspane and added to: " + jc);

            if (autoLayout) {
                if (lastClickedContainer != null) {
                    lastClickedContainer.revalidate();
                    lastClickedContainer.repaint();
                }
                droppedComponent.revalidate();
                droppedComponent.repaint();
                jc.revalidate();
                jc.repaint();
            }

        } else {
            glassPane.removeAll();
            glassPane.revalidate();
            glassPane.repaint();
            if (lastClickedContainer != null) {
                lastClickedContainer.add(droppedComponent);
                lastClickedContainer.revalidate();
                lastClickedContainer.repaint();
            }
        }
    }

    protected void componentPressed(MouseEvent me) {
        JComponent jc = findDroppableUnderGlassPane(me.getPoint(), container.getContentPane(), (Component) me.getSource());

        if (jc != null && jc.getName().equals("Droppable")) {
            lastClickedContainer = jc;
            System.out.println("Pressed: " + lastClickedContainer);
        }

        boolean clickedRegisteredComponent = false;

        Component clickedComponent = (Component) me.getSource();

        for (Component component : ComponentDrag.this.components) {
            if (component.equals(clickedComponent)) {
                clickedRegisteredComponent = true;
                break;
            }
        }

        if (clickedRegisteredComponent) {
            startingX = me.getX();
            startingY = me.getY();
            clickedComponent.setCursor(new Cursor(Cursor.MOVE_CURSOR));
        }
    }

    protected void componentDragged(MouseEvent me) {
        Component draggedComponent = (Component) me.getSource();

        if (firstTime && lastClickedContainer != null) {
            firstTime = false;
            lastClickedContainer.remove(draggedComponent);
            lastClickedContainer.revalidate();
            lastClickedContainer.repaint();
            glassPane.add(draggedComponent);
            glassPane.revalidate();
            glassPane.repaint();
            System.out.println("Removed from: " + lastClickedContainer + " \nAnd added to glasspane for dragging");
        }

        //MouseEvent will refire on each drag with the position being relative to the firing Component
        draggedComponent.setLocation((me.getX() - startingX) + draggedComponent.getLocation().x, (me.getY() - startingY) + draggedComponent.getLocation().y);
    }

    void registerComponent(JComponent draggableComp) {
        draggableComp.addMouseListener(ma);
        draggableComp.addMouseMotionListener(ma);
        components.add(draggableComp);
    }

    void deregisterComponent(JComponent draggableComp) {
        draggableComp.removeMouseListener(ma);
        draggableComp.removeMouseMotionListener(ma);
        components.remove(draggableComp);
    }
}