2012-08-05 42 views
2

我正在使用拖放方式在四个组件中的一个上放置按钮。为了让它更具吸引力,而不仅仅是鼠标指示被拖动的东西(这工作正常),我想实时显示它。这适用,除非鼠标移回被拖动的组件,拖动监听器将注册一个dragExit事件,该事件会删除导致侦听器重新聚焦到父组件并激发导致闪烁的dragEnter的按钮。我需要使按钮不会影响拖动监听器。有任何想法吗?实时拖放在Swing中

dragging a DndButton that says hello between four DndLabels

这是我加入它太的JLabel(我知道的JLabel是不是一个好的选择,但它运作良好,可以轻松地显示,我需要的图像)

import java.awt.Point; 
import java.awt.datatransfer.DataFlavor; 
import java.awt.datatransfer.Transferable; 
import java.awt.datatransfer.UnsupportedFlavorException; 
import java.awt.dnd.*; 
import java.io.IOException; 
import javax.swing.*; 


//and here is the button to drag 
public class DndLabel extends JLabel implements DropTargetListener { 

    private DropTarget target; 
    private DndButton button; 
    public DndLabel last; 

    //initialize the JTable with the data 
    public DndLabel() { 
     super(); 

     //mark this a DropTarget 
     target = new DropTarget(this, this); 

     //have it utilize a custom transfer handler 
     setTransferHandler(new MyTransferHandler()); 
    } 

    public void dragEnter(DropTargetDragEvent dtde) { 
     System.out.println("enter"); 

     try { 
      //get the Point where the drop occurred 
      Point loc = dtde.getLocation(); 

      //get Transfer data 
      Transferable t = dtde.getTransferable(); 

      //get the Data flavors transferred with the Transferable 
      DataFlavor[] d = t.getTransferDataFlavors(); 

      button = (DndButton) t.getTransferData(d[0]); 

      button.setBounds(loc.x, 0, 100, 50); 

      add(button); 

      //and if the DataFlavors match for the DnDTable 
      //(ie., we don't want an ImageFlavor marking an image transfer) 
      if (getTransferHandler().canImport(this, d)) { 

       //then import the Draggable JComponent and repaint() the JTable 
       ((MyTransferHandler) getTransferHandler()).importData(this, (DndButton) t.getTransferData(d[0]), loc); 
       repaint(); 
      } else { 
       return; 
      } 
     } catch (UnsupportedFlavorException ex) { 
      ex.printStackTrace(); 
     } catch(IOException ex){ 
      ex.printStackTrace(); 
     } 
    } 

    @Override 
    public void dragOver(DropTargetDragEvent dtde) { 
     button.setLocation(dtde.getLocation().x, 0); 
    } 

    public void dragExit(DropTargetEvent dte) { 
     System.out.println("remove"); 

     last = null; 
     remove(button); 
     repaint(); 

    } 

    //This is what happens when a Drop occurs 
    public void drop(DropTargetDropEvent dtde) { 
     System.out.println("drop!"); 
     try { 
      //get the Point where the drop occurred 
      Point loc = dtde.getLocation(); 

      //get Transfer data 
      Transferable t = dtde.getTransferable(); 

      //get the Data flavors transferred with the Transferable 
      DataFlavor[] d = t.getTransferDataFlavors(); 

      DndButton tempButton = (DndButton) t.getTransferData(d[0]); 

      tempButton.setBounds(loc.x, 0, 100, 50); 

      add(tempButton); 

      //and if the DataFlavors match for the DnDTable 
      //(ie., we don't want an ImageFlavor marking an image transfer) 
      if (getTransferHandler().canImport(this, d)) { 

       //then import the Draggable JComponent and repaint() the JTable 
       ((MyTransferHandler) getTransferHandler()).importData(this, (DndButton) t.getTransferData(d[0]), loc); 
       repaint(); 
      } else { 
       return; 
      } 

     } catch (UnsupportedFlavorException ex) { 
      ex.printStackTrace(); 
     }catch(IOException ex){ 

     }finally { 
      dtde.dropComplete(true); 
     } 
    } 

    @Override 
    public void dropActionChanged(DropTargetDragEvent dtde) { 
    } 

    class MyTransferHandler extends TransferHandler { 

     //tests for a valid JButton DataFlavor 
     public boolean canImport(JComponent c, DataFlavor[] f) { 
      DataFlavor temp = new DataFlavor(DndButton.class, "JButton"); 
      for (DataFlavor d : f) { 
       if (d.equals(temp)) { 
        return true; 
       } 

      } 
      return false; 
     } 

     //add the data into the JTable 
     public boolean importData(JComponent comp, Transferable t, Point p) { 
      try { 
       DndButton tempButton = (DndButton) t.getTransferData(new DataFlavor(DndButton.class, "JButton")); 

      } catch (UnsupportedFlavorException | IOException ex) { 
       System.err.println(ex); 
      } 
      return true; 
     } 
    } 
} 
class DndButton extends JButton implements Transferable, DragSourceListener, DragGestureListener { 

    //marks this JButton as the source of the Drag 
    private DragSource source; 
    private TransferHandler t; 

    public DndButton() { 
     this(""); 
    } 

    public DndButton(String message) { 
     super(message); 

     //The TransferHandler returns a new DnDButton 
     //to be transferred in the Drag 
     t = new TransferHandler() { 

      public Transferable createTransferable(JComponent c) { 
       return new DndButton(getText()); 
      } 
     }; 
     setTransferHandler(t); 

     //The Drag will copy the DnDButton rather than moving it 
     source = new DragSource(); 
     source.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_MOVE, this); 
    } 

    //The DataFlavor is a marker to let the DropTarget know how to 
    //handle the Transferable 
    public DataFlavor[] getTransferDataFlavors() { 
     return new DataFlavor[]{new DataFlavor(DndButton.class, "JButton")}; 
    } 

    public boolean isDataFlavorSupported(DataFlavor flavor) { 
     return true; 
    } 

    public Object getTransferData(DataFlavor flavor) { 
     return this; 
    } 

    public void dragEnter(DragSourceDragEvent dsde) { 
    } 

    public void dragOver(DragSourceDragEvent dsde) { 
     //this.setLocation(dsde.getX()-150,0); 
    } 

    public void dropActionchanged(DragSourceDragEvent dsde) { 
    } 

    public void dragExit(DragSourceEvent dse) { 
    } 

    //when the drag finishes, then repaint the DnDButton 
    //so it doesn't look like it has still been pressed down 
    public void dragDropEnd(DragSourceDropEvent dsde) { 
     // JComponent c = (JComponent) this.getParent(); 
     //c.remove(this); 
     //c.repaint(); 
    } 

    //when a DragGesture is recognized, initiate the Drag 
    public void dragGestureRecognized(DragGestureEvent dge) { 
     source.startDrag(dge, DragSource.DefaultMoveDrop, DndButton.this, this); 
    } 

    @Override 
    public void dropActionChanged(DragSourceDragEvent dsde) { 
    } 
} 

class Main { 

    public static void main(String[] args) { 
     JFrame f = new JFrame("sscce"); 
     f.setBounds(0, 0, 500, 80); 
     f.setVisible(true); 
     DndLabel trackOne = new DndLabel(); 
     trackOne.setBounds(0, 0, 500, 50); 
     f.add(trackOne); 
     DndButton b = new DndButton("hello"); 
     b.setBounds(0, 0, 100, trackOne.getHeight()); 

     trackOne.add(b); 
     trackOne.revalidate(); 
     trackOne.repaint(); 
    } 
} 
+1

为了更好的帮助更快,张贴[SSCCE](http://sscce.org/ )。 – 2012-08-05 01:37:43

+0

@Andrew Thompson好的我将代码更改为SSCCE – ghostbust555 2012-08-05 01:53:28

回答

4

我个人可能会拒绝这样做。问题是,每次添加组件时,组件都会干扰层次结构中的鼠标侦听器,从而导致向容器通知退出事件,这会导致按钮被移除并且容器将被通知输入事件并且循环继续。

就我个人而言,我会做两件事之一。我要么

  • 油漆到玻璃面板上的按钮的表示或
  • 油漆拖动面板

这消除了按钮的引起与干扰的可能性上的按钮的表示涉及鼠标听众。

结帐My Drag Image is Better than Yours。虽然你在那里挖了一下,蒂姆做了一些优秀的文章drag'n'drop这是值得的阅读

+0

很好的答案和链接非常感谢! – ghostbust555 2012-08-05 17:35:38

+0

是的,我喜欢蒂姆的东西,真的帮助了我 – MadProgrammer 2012-08-05 19:31:58