2012-08-05 48 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