java - Swing 事件未向上传递到基础组件

标签 java swing drag-and-drop parent-child

我有一个名为 ComponentMover 的类,它允许您拖动向其注册的任何对象。如果您传递裸露的 JPanel,则此方法有效,但如果 JPanel 内部有任何内容,则此方法不起作用,并且它只是保持原样。

这是 ComponentMover:

public class ComponentMover extends MouseAdapter {
    private Insets dragInsets = new Insets(0, 0, 0, 0);
    private Dimension snapSize = new Dimension(1, 1);
    private Insets edgeInsets = new Insets(0, 0, 0, 0);
    private boolean changeCursor = true;
    private boolean autoLayout = false;

    private Class<?> destinationClass;
    private Component destinationComponent;
    private Component destination;
    private Component source;

    private Point pressed;
    private Point location;

    private Cursor originalCursor;
    private boolean autoscrolls;
    private boolean potentialDrag;

    private boolean shouldLock = true;

    /**
     * Constructor for moving individual components. The components must be
     * regisetered using the registerComponent() method.
     */
    public ComponentMover() {
    }

    /**
     * Constructor to specify a Class of Component that will be moved when drag
     * events are generated on a registered child component. The events will be
     * passed to the first ancestor of this specified class.
     *
     * @param destinationClass
     *            the Class of the ancestor component
     * @param component
     *            the Components to be registered for forwarding drag events to
     *            the ancestor Component.
     */
    public ComponentMover(Class<?> destinationClass, JComponent... components) {
        this.destinationClass = destinationClass;
        registerComponent(components);
    }

    /**
     * Constructor to specify a parent component that will be moved when drag
     * events are generated on a registered child component.
     *
     * @param destinationComponent
     *            the component drage events should be forwareded to
     * @param components
     *            the Components to be registered for forwarding drag events to
     *            the parent component to be moved
     */
    public ComponentMover(JComponent destinationComponent,
            JComponent... components) {
        this.destinationComponent = destinationComponent;
        registerComponent(components);
    }

    public void setLock(boolean shouldLock) {
        this.shouldLock = shouldLock;
    }

    /**
     * Get the auto layout property
     *
     * @return the auto layout property
     */
    public boolean isAutoLayout() {
        return autoLayout;
    }

    /**
     * Set the auto layout property
     *
     * @param autoLayout
     *            when true layout will be invoked on the parent container
     */
    public void setAutoLayout(boolean autoLayout) {
        this.autoLayout = autoLayout;
    }

    /**
     * Get the change cursor property
     *
     * @return the change cursor property
     */
    public boolean isChangeCursor() {
        return changeCursor;
    }

    /**
     * Set the change cursor property
     *
     * @param changeCursor
     *            when true the cursor will be changed to the Cursor.MOVE_CURSOR
     *            while the mouse is pressed
     */
    public void setChangeCursor(boolean changeCursor) {
        this.changeCursor = changeCursor;
    }

    /**
     * Get the drag insets
     *
     * @return the drag insets
     */
    public Insets getDragInsets() {
        return dragInsets;
    }

    /**
     * Set the drag insets. The insets specify an area where mouseDragged events
     * should be ignored and therefore the component will not be moved. This
     * will prevent these events from being confused with a MouseMotionListener
     * that supports component resizing.
     *
     * @param dragInsets
     */
    public void setDragInsets(Insets dragInsets) {
        this.dragInsets = dragInsets;
    }

    /**
     * Get the bounds insets
     *
     * @return the bounds insets
     */
    public Insets getEdgeInsets() {
        return edgeInsets;
    }

    /**
     * Set the edge insets. The insets specify how close to each edge of the
     * parent component that the child component can be moved. Positive values
     * means the component must be contained within the parent. Negative values
     * means the component can be moved outside the parent.
     *
     * @param edgeInsets
     */
    public void setEdgeInsets(Insets edgeInsets) {
        this.edgeInsets = edgeInsets;
    }

    /**
     * Remove listeners from the specified component
     *
     * @param component
     *            the component the listeners are removed from
     */
    public void deregisterComponent(JComponent... components) {
        for (JComponent component : components)
            component.removeMouseListener(this);
    }

    /**
     * Add the required listeners to the specified component
     *
     * @param component
     *            the component the listeners are added to
     */
    public void registerComponent(JComponent... components) {
        for (JComponent component : components){
            component.addMouseListener(this);
        }
    }

    /**
     * Get the snap size
     *
     * @return the snap size
     */
    public Dimension getSnapSize() {
        return snapSize;
    }

    /**
     * Set the snap size. Forces the component to be snapped to the closest grid
     * position. Snapping will occur when the mouse is dragged half way.
     */
    public void setSnapSize(Dimension snapSize) {
        if (snapSize.width < 1 || snapSize.height < 1)
            throw new IllegalArgumentException(
                    "Snap sizes must be greater than 0");

        this.snapSize = snapSize;
    }

    /**
     * Setup the variables used to control the moving of the component:
     *
     * source - the source component of the mouse event destination - the
     * component that will ultimately be moved pressed - the Point where the
     * mouse was pressed in the destination component coordinates.
     */
    @Override
    public void mousePressed(MouseEvent e) {
        source = e.getComponent();
        int width = source.getSize().width - dragInsets.left - dragInsets.right;
        int height = source.getSize().height - dragInsets.top
                - dragInsets.bottom;
        Rectangle r = new Rectangle(dragInsets.left, dragInsets.top, width,
                height);

        if (r.contains(e.getPoint()))
            setupForDragging(e);
    }

    private void setupForDragging(MouseEvent e) {
        source.addMouseMotionListener(this);
        potentialDrag = true;

        // Determine the component that will ultimately be moved

        if (destinationComponent != null) {
            destination = destinationComponent;
        } else if (destinationClass == null) {
            destination = source;
        } else // forward events to destination component
        {
            destination = SwingUtilities.getAncestorOfClass(destinationClass,
                    source);
        }

        pressed = e.getLocationOnScreen();
        location = destination.getLocation();

        if (changeCursor) {
            originalCursor = source.getCursor();
            source.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
        }

        // Making sure autoscrolls is false will allow for smoother dragging of
        // individual components

        if (destination instanceof JComponent) {
            JComponent jc = (JComponent) destination;
            autoscrolls = jc.getAutoscrolls();
            jc.setAutoscrolls(false);
        }
    }

    /**
     * Move the component to its new location. The dragged Point must be in the
     * destination coordinates.
     */
    @Override
    public void mouseDragged(MouseEvent e) {
        Point dragged = e.getLocationOnScreen();
        int dragX = getDragDistance(dragged.x, pressed.x, snapSize.width);
        int dragY = getDragDistance(dragged.y, pressed.y, snapSize.height);

        int locationX = location.x + dragX;
        int locationY = location.y + dragY;

        // Mouse dragged events are not generated for every pixel the mouse
        // is moved. Adjust the location to make sure we are still on a
        // snap value.

        if (shouldLock) {
            while (locationX < edgeInsets.left)
                locationX += snapSize.width;

            while (locationY < edgeInsets.top)
                locationY += snapSize.height;

            Dimension d = getBoundingSize(destination);

            while (locationX + destination.getSize().width + edgeInsets.right > d.width)
                locationX -= snapSize.width;

            while (locationY + destination.getSize().height + edgeInsets.bottom > d.height)
                locationY -= snapSize.height;
        }
        // Adjustments are finished, move the component

        destination.setLocation(locationX, locationY);
    }

    /*
     * Determine how far the mouse has moved from where dragging started (Assume
     * drag direction is down and right for positive drag distance)
     */
    private int getDragDistance(int larger, int smaller, int snapSize) {
        int halfway = snapSize / 2;
        int drag = larger - smaller;
        drag += (drag < 0) ? -halfway : halfway;
        drag = (drag / snapSize) * snapSize;

        return drag;
    }

    /*
     * Get the bounds of the parent of the dragged component.
     */
    private Dimension getBoundingSize(Component source) {
        if (source instanceof Window) {
            GraphicsEnvironment env = GraphicsEnvironment
                    .getLocalGraphicsEnvironment();
            Rectangle bounds = env.getMaximumWindowBounds();
            return new Dimension(bounds.width, bounds.height);
        } else {
            return source.getParent().getSize();
        }
    }

    /**
     * Restore the original state of the Component
     */
    @Override
    public void mouseReleased(MouseEvent e) {
        if (!potentialDrag)
            return;

        source.removeMouseMotionListener(this);
        potentialDrag = false;

        if (changeCursor)
            source.setCursor(originalCursor);

        if (destination instanceof JComponent) {
            ((JComponent) destination).setAutoscrolls(autoscrolls);
        }

        // Layout the components on the parent container

        if (autoLayout) {
            if (destination instanceof JComponent) {
                ((JComponent) destination).revalidate();
            } else {
                destination.validate();
            }
        }
    }
}

我应该如何处理此代码(或其他 GUI 的构建代码)才能使我能够拖放子组件?

最佳答案

您有一个 ComponentMover 的改编版作者:@camickr。原始版本和您的版本可以很好地与有子组件的组件配合使用。也许问题出在其他地方。考虑发布MCVE这就说明了问题。

这是一个简单的演示:

enter image description here

import java.awt.Color;
import java.awt.Dimension;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class TestMove extends JPanel{
    public TestMove() {
        setLayout(null);

        JPanel panel = new JPanel();
        panel.add(new JLabel("label"));
        panel.add(new JButton("button"));

        panel.setBorder(BorderFactory.createLineBorder(Color.GREEN));
        panel.setBounds(50, 50, 200, 50);

        add(panel);

        ComponentMover cm = new ComponentMover();
        cm.registerComponent(panel);
    }

    public Dimension getPreferredSize() {
        return new Dimension(300, 200);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {   
            public void run() {   
                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLocationByPlatform(true);

                TestMove panel = new TestMove();
                frame.add(panel);
                frame.pack();

                frame.setVisible(true);
            }
        });

    }
}

关于java - Swing 事件未向上传递到基础组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24686116/

相关文章:

java - 如何通过将颜色更改为红色来显示正在排序的行?

java - 泛型类方法调用

java - 使用java swing调用另一个类的方法来绘制当前类

javascript - 使用拖放的纯 javascript 和 css 分割器代码,光标问题

javascript - 是否有任何 Javascript 库提供表单元素的拖放创建/编辑?

java - 需要 QC12.21 的 COM4j.jar 文件

java - JAXB 父节点和子节点同名。子节点返回空值

java - 在 GridBagLayout 中调用 SetContraints 时出现 NullPointerException

java - ArrayIndexOutOfBoundsException 错误,但我认为代码没问题

javascript - 如何从 angular 2 onDrop 事件中获取文件?