2014-07-10 76 views
0

我有一個名爲ComponentMover的類,它允許您拖動任何已註冊的對象。如果你將它傳遞給JPanels,它會起作用,但如果JPanel內部有任何東西,它就不起作用,它只是保持放置狀態。未向上傳遞到基本組件的Swing事件

這是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的建築規範),以使我能夠拖動和兒童組件拖放?

回答

4

您有@camickr改編的ComponentMover。原始版本和您的版本適用於有孩子的組件。也許問題在別處。考慮發佈一個說明問題的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); 
      } 
     }); 

    } 
} 
+1

嗯....好吧,謝謝你。如果有人需要我,我會瘋狂地調試。 – Kyranstar

+0

@Kyranstar不客氣!我很高興它幫助:) – tenorsax