2008-09-13 73 views

Trả lời

12

tôi thích Terai Atsuhiro san's DnDTabbedPane, nhưng tôi muốn nhiều hơn từ nó. Việc triển khai Terai ban đầu đã chuyển các tab trong TabbedPane, nhưng nó sẽ đẹp hơn nếu tôi có thể kéo từ một TabbedPane này sang một TabbedPane khác.

Lấy cảm hứng từ nỗ lực của @Tom, tôi quyết định tự sửa đổi mã. Có một số chi tiết tôi đã thêm. Ví dụ, tab ghost bây giờ trượt dọc theo ngăn theo thẻ thay vì di chuyển cùng với con chuột.

setAcceptor(TabAcceptor a_acceptor) nên để mã người tiêu dùng quyết định có cho phép chuyển tab từ một ngăn tab sang tab khác hay không. Người chấp nhận mặc định luôn trả về true.

/** Modified DnDTabbedPane.java 
* http://java-swing-tips.blogspot.com/2008/04/drag-and-drop-tabs-in-jtabbedpane.html 
* originally written by Terai Atsuhiro. 
* so that tabs can be transfered from one pane to another. 
* eed3si9n. 
*/ 

import java.awt.*; 
import java.awt.datatransfer.*; 
import java.awt.dnd.*; 
import java.awt.geom.*; 
import java.awt.image.*; 
import javax.swing.*; 

public class DnDTabbedPane extends JTabbedPane { 
    public static final long serialVersionUID = 1L; 
    private static final int LINEWIDTH = 3; 
    private static final String NAME = "TabTransferData"; 
    private final DataFlavor FLAVOR = new DataFlavor(
      DataFlavor.javaJVMLocalObjectMimeType, NAME); 
    private static GhostGlassPane s_glassPane = new GhostGlassPane(); 

    private boolean m_isDrawRect = false; 
    private final Rectangle2D m_lineRect = new Rectangle2D.Double(); 

    private final Color m_lineColor = new Color(0, 100, 255); 
    private TabAcceptor m_acceptor = null; 

    public DnDTabbedPane() { 
     super(); 
     final DragSourceListener dsl = new DragSourceListener() { 
      public void dragEnter(DragSourceDragEvent e) { 
       e.getDragSourceContext().setCursor(DragSource.DefaultMoveDrop); 
      } 

      public void dragExit(DragSourceEvent e) { 
       e.getDragSourceContext() 
         .setCursor(DragSource.DefaultMoveNoDrop); 
       m_lineRect.setRect(0, 0, 0, 0); 
       m_isDrawRect = false; 
       s_glassPane.setPoint(new Point(-1000, -1000)); 
       s_glassPane.repaint(); 
      } 

      public void dragOver(DragSourceDragEvent e) { 
       //e.getLocation() 
       //This method returns a Point indicating the cursor location in screen coordinates at the moment 

       TabTransferData data = getTabTransferData(e); 
       if (data == null) { 
        e.getDragSourceContext().setCursor(
          DragSource.DefaultMoveNoDrop); 
        return; 
       } // if 

       /* 
       Point tabPt = e.getLocation(); 
       SwingUtilities.convertPointFromScreen(tabPt, DnDTabbedPane.this); 
       if (DnDTabbedPane.this.contains(tabPt)) { 
        int targetIdx = getTargetTabIndex(tabPt); 
        int sourceIndex = data.getTabIndex(); 
        if (getTabAreaBound().contains(tabPt) 
          && (targetIdx >= 0) 
          && (targetIdx != sourceIndex) 
          && (targetIdx != sourceIndex + 1)) { 
         e.getDragSourceContext().setCursor(
           DragSource.DefaultMoveDrop); 

         return; 
        } // if 

        e.getDragSourceContext().setCursor(
          DragSource.DefaultMoveNoDrop); 
        return; 
       } // if 
       */ 

       e.getDragSourceContext().setCursor(
         DragSource.DefaultMoveDrop); 
      } 

      public void dragDropEnd(DragSourceDropEvent e) { 
       m_isDrawRect = false; 
       m_lineRect.setRect(0, 0, 0, 0); 
       // m_dragTabIndex = -1; 

       if (hasGhost()) { 
        s_glassPane.setVisible(false); 
        s_glassPane.setImage(null); 
       } 
      } 

      public void dropActionChanged(DragSourceDragEvent e) { 
      } 
     }; 

     final DragGestureListener dgl = new DragGestureListener() { 
      public void dragGestureRecognized(DragGestureEvent e) { 
       // System.out.println("dragGestureRecognized"); 

       Point tabPt = e.getDragOrigin(); 
       int dragTabIndex = indexAtLocation(tabPt.x, tabPt.y); 
       if (dragTabIndex < 0) { 
        return; 
       } // if 

       initGlassPane(e.getComponent(), e.getDragOrigin(), dragTabIndex); 
       try { 
        e.startDrag(DragSource.DefaultMoveDrop, 
          new TabTransferable(DnDTabbedPane.this, dragTabIndex), dsl); 
       } catch (InvalidDnDOperationException idoe) { 
        idoe.printStackTrace(); 
       } 
      } 
     }; 

     //dropTarget = 
     new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, 
       new CDropTargetListener(), true); 
     new DragSource().createDefaultDragGestureRecognizer(this, 
       DnDConstants.ACTION_COPY_OR_MOVE, dgl); 
     m_acceptor = new TabAcceptor() { 
      public boolean isDropAcceptable(DnDTabbedPane a_component, int a_index) { 
       return true; 
      } 
     }; 
    } 

    public TabAcceptor getAcceptor() { 
     return m_acceptor; 
    } 

    public void setAcceptor(TabAcceptor a_value) { 
     m_acceptor = a_value; 
    } 

    private TabTransferData getTabTransferData(DropTargetDropEvent a_event) {  
     try { 
      TabTransferData data = (TabTransferData) a_event.getTransferable().getTransferData(FLAVOR);    
      return data; 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     return null; 
    } 

    private TabTransferData getTabTransferData(DropTargetDragEvent a_event) { 
     try { 
      TabTransferData data = (TabTransferData) a_event.getTransferable().getTransferData(FLAVOR);    
      return data; 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     return null; 
    } 

    private TabTransferData getTabTransferData(DragSourceDragEvent a_event) { 
     try { 
      TabTransferData data = (TabTransferData) a_event.getDragSourceContext() 
       .getTransferable().getTransferData(FLAVOR);    
      return data; 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     return null;   
    } 

    class TabTransferable implements Transferable { 
     private TabTransferData m_data = null; 

     public TabTransferable(DnDTabbedPane a_tabbedPane, int a_tabIndex) { 
      m_data = new TabTransferData(DnDTabbedPane.this, a_tabIndex); 
     } 

     public Object getTransferData(DataFlavor flavor) { 
      return m_data; 
      // return DnDTabbedPane.this; 
     } 

     public DataFlavor[] getTransferDataFlavors() { 
      DataFlavor[] f = new DataFlavor[1]; 
      f[0] = FLAVOR; 
      return f; 
     } 

     public boolean isDataFlavorSupported(DataFlavor flavor) { 
      return flavor.getHumanPresentableName().equals(NAME); 
     }  
    } 

    class TabTransferData { 
     private DnDTabbedPane m_tabbedPane = null; 
     private int m_tabIndex = -1; 

     public TabTransferData() { 
     } 

     public TabTransferData(DnDTabbedPane a_tabbedPane, int a_tabIndex) { 
      m_tabbedPane = a_tabbedPane; 
      m_tabIndex = a_tabIndex; 
     } 

     public DnDTabbedPane getTabbedPane() { 
      return m_tabbedPane; 
     } 

     public void setTabbedPane(DnDTabbedPane pane) { 
      m_tabbedPane = pane; 
     } 

     public int getTabIndex() { 
      return m_tabIndex; 
     } 

     public void setTabIndex(int index) { 
      m_tabIndex = index; 
     } 
    } 

    private Point buildGhostLocation(Point a_location) { 
     Point retval = new Point(a_location); 

     switch (getTabPlacement()) { 
      case JTabbedPane.TOP: { 
       retval.y = 1; 
       retval.x -= s_glassPane.getGhostWidth()/2; 
      } break; 

      case JTabbedPane.BOTTOM: { 
       retval.y = getHeight() - 1 - s_glassPane.getGhostHeight(); 
       retval.x -= s_glassPane.getGhostWidth()/2; 
      } break; 

      case JTabbedPane.LEFT: { 
       retval.x = 1; 
       retval.y -= s_glassPane.getGhostHeight()/2; 
      } break; 

      case JTabbedPane.RIGHT: { 
       retval.x = getWidth() - 1 - s_glassPane.getGhostWidth(); 
       retval.y -= s_glassPane.getGhostHeight()/2; 
      } break; 
     } // switch 

     retval = SwingUtilities.convertPoint(DnDTabbedPane.this, 
       retval, s_glassPane); 
     return retval; 
    } 

    class CDropTargetListener implements DropTargetListener { 
     public void dragEnter(DropTargetDragEvent e) { 
      // System.out.println("DropTarget.dragEnter: " + DnDTabbedPane.this); 

      if (isDragAcceptable(e)) { 
       e.acceptDrag(e.getDropAction()); 
      } else { 
       e.rejectDrag(); 
      } // if 
     } 

     public void dragExit(DropTargetEvent e) { 
      // System.out.println("DropTarget.dragExit: " + DnDTabbedPane.this); 
      m_isDrawRect = false; 
     } 

     public void dropActionChanged(DropTargetDragEvent e) { 
     } 

     public void dragOver(final DropTargetDragEvent e) { 
      TabTransferData data = getTabTransferData(e); 

      if (getTabPlacement() == JTabbedPane.TOP 
        || getTabPlacement() == JTabbedPane.BOTTOM) { 
       initTargetLeftRightLine(getTargetTabIndex(e.getLocation()), data); 
      } else { 
       initTargetTopBottomLine(getTargetTabIndex(e.getLocation()), data); 
      } // if-else 

      repaint(); 
      if (hasGhost()) { 
       s_glassPane.setPoint(buildGhostLocation(e.getLocation())); 
       s_glassPane.repaint(); 
      } 
     } 

     public void drop(DropTargetDropEvent a_event) { 
      // System.out.println("DropTarget.drop: " + DnDTabbedPane.this); 

      if (isDropAcceptable(a_event)) { 
       convertTab(getTabTransferData(a_event), 
        getTargetTabIndex(a_event.getLocation())); 
       a_event.dropComplete(true); 
      } else { 
       a_event.dropComplete(false); 
      } // if-else 

      m_isDrawRect = false; 
      repaint(); 
     } 

     public boolean isDragAcceptable(DropTargetDragEvent e) { 
      Transferable t = e.getTransferable(); 
      if (t == null) { 
       return false; 
      } // if 

      DataFlavor[] flavor = e.getCurrentDataFlavors(); 
      if (!t.isDataFlavorSupported(flavor[0])) { 
       return false; 
      } // if 

      TabTransferData data = getTabTransferData(e); 

      if (DnDTabbedPane.this == data.getTabbedPane() 
        && data.getTabIndex() >= 0) { 
       return true; 
      } // if 

      if (DnDTabbedPane.this != data.getTabbedPane()) { 
       if (m_acceptor != null) { 
        return m_acceptor.isDropAcceptable(data.getTabbedPane(), data.getTabIndex()); 
       } // if 
      } // if 

      return false; 
     } 

     public boolean isDropAcceptable(DropTargetDropEvent e) { 
      Transferable t = e.getTransferable(); 
      if (t == null) { 
       return false; 
      } // if 

      DataFlavor[] flavor = e.getCurrentDataFlavors(); 
      if (!t.isDataFlavorSupported(flavor[0])) { 
       return false; 
      } // if 

      TabTransferData data = getTabTransferData(e); 

      if (DnDTabbedPane.this == data.getTabbedPane() 
        && data.getTabIndex() >= 0) { 
       return true; 
      } // if 

      if (DnDTabbedPane.this != data.getTabbedPane()) { 
       if (m_acceptor != null) { 
        return m_acceptor.isDropAcceptable(data.getTabbedPane(), data.getTabIndex()); 
       } // if 
      } // if 

      return false; 
     } 
    } 

    private boolean m_hasGhost = true; 

    public void setPaintGhost(boolean flag) { 
     m_hasGhost = flag; 
    } 

    public boolean hasGhost() { 
     return m_hasGhost; 
    } 

    /** 
    * returns potential index for drop. 
    * @param a_point point given in the drop site component's coordinate 
    * @return returns potential index for drop. 
    */ 
    private int getTargetTabIndex(Point a_point) { 
     boolean isTopOrBottom = getTabPlacement() == JTabbedPane.TOP 
       || getTabPlacement() == JTabbedPane.BOTTOM; 

     // if the pane is empty, the target index is always zero. 
     if (getTabCount() == 0) { 
      return 0; 
     } // if 

     for (int i = 0; i < getTabCount(); i++) { 
      Rectangle r = getBoundsAt(i); 
      if (isTopOrBottom) { 
       r.setRect(r.x - r.width/2, r.y, r.width, r.height); 
      } else { 
       r.setRect(r.x, r.y - r.height/2, r.width, r.height); 
      } // if-else 

      if (r.contains(a_point)) { 
       return i; 
      } // if 
     } // for 

     Rectangle r = getBoundsAt(getTabCount() - 1); 
     if (isTopOrBottom) { 
      int x = r.x + r.width/2; 
      r.setRect(x, r.y, getWidth() - x, r.height); 
     } else { 
      int y = r.y + r.height/2; 
      r.setRect(r.x, y, r.width, getHeight() - y); 
     } // if-else 

     return r.contains(a_point) ? getTabCount() : -1; 
    } 

    private void convertTab(TabTransferData a_data, int a_targetIndex) { 
     DnDTabbedPane source = a_data.getTabbedPane(); 
     int sourceIndex = a_data.getTabIndex(); 
     if (sourceIndex < 0) { 
      return; 
     } // if 

     Component cmp = source.getComponentAt(sourceIndex); 
     String str = source.getTitleAt(sourceIndex); 
     if (this != source) { 
      source.remove(sourceIndex); 

      if (a_targetIndex == getTabCount()) { 
       addTab(str, cmp); 
      } else { 
       if (a_targetIndex < 0) { 
        a_targetIndex = 0; 
       } // if 

       insertTab(str, null, cmp, null, a_targetIndex); 

      } // if 

      setSelectedComponent(cmp); 
      // System.out.println("press="+sourceIndex+" next="+a_targetIndex); 
      return; 
     } // if 

     if (a_targetIndex < 0 || sourceIndex == a_targetIndex) { 
      //System.out.println("press="+prev+" next="+next); 
      return; 
     } // if 

     if (a_targetIndex == getTabCount()) { 
      //System.out.println("last: press="+prev+" next="+next); 
      source.remove(sourceIndex); 
      addTab(str, cmp); 
      setSelectedIndex(getTabCount() - 1); 
     } else if (sourceIndex > a_targetIndex) { 
      //System.out.println(" >: press="+prev+" next="+next); 
      source.remove(sourceIndex); 
      insertTab(str, null, cmp, null, a_targetIndex); 
      setSelectedIndex(a_targetIndex); 
     } else { 
      //System.out.println(" <: press="+prev+" next="+next); 
      source.remove(sourceIndex); 
      insertTab(str, null, cmp, null, a_targetIndex - 1); 
      setSelectedIndex(a_targetIndex - 1); 
     } 
    } 

    private void initTargetLeftRightLine(int next, TabTransferData a_data) {   
     if (next < 0) { 
      m_lineRect.setRect(0, 0, 0, 0); 
      m_isDrawRect = false; 
      return; 
     } // if 

     if ((a_data.getTabbedPane() == this) 
       && (a_data.getTabIndex() == next 
       || next - a_data.getTabIndex() == 1)) { 
      m_lineRect.setRect(0, 0, 0, 0); 
      m_isDrawRect = false; 
     } else if (getTabCount() == 0) { 
      m_lineRect.setRect(0, 0, 0, 0); 
      m_isDrawRect = false; 
      return; 
     } else if (next == 0) { 
      Rectangle rect = getBoundsAt(0); 
      m_lineRect.setRect(-LINEWIDTH/2, rect.y, LINEWIDTH, rect.height); 
      m_isDrawRect = true; 
     } else if (next == getTabCount()) { 
      Rectangle rect = getBoundsAt(getTabCount() - 1); 
      m_lineRect.setRect(rect.x + rect.width - LINEWIDTH/2, rect.y, 
        LINEWIDTH, rect.height); 
      m_isDrawRect = true; 
     } else { 
      Rectangle rect = getBoundsAt(next - 1); 
      m_lineRect.setRect(rect.x + rect.width - LINEWIDTH/2, rect.y, 
        LINEWIDTH, rect.height); 
      m_isDrawRect = true; 
     } 
    } 

    private void initTargetTopBottomLine(int next, TabTransferData a_data) { 
     if (next < 0) { 
      m_lineRect.setRect(0, 0, 0, 0); 
      m_isDrawRect = false; 
      return; 
     } // if 

     if ((a_data.getTabbedPane() == this) 
       && (a_data.getTabIndex() == next 
       || next - a_data.getTabIndex() == 1)) { 
      m_lineRect.setRect(0, 0, 0, 0); 
      m_isDrawRect = false; 
     } else if (getTabCount() == 0) { 
      m_lineRect.setRect(0, 0, 0, 0); 
      m_isDrawRect = false; 
      return; 
     } else if (next == getTabCount()) { 
      Rectangle rect = getBoundsAt(getTabCount() - 1); 
      m_lineRect.setRect(rect.x, rect.y + rect.height - LINEWIDTH/2, 
        rect.width, LINEWIDTH); 
      m_isDrawRect = true; 
     } else if (next == 0) { 
      Rectangle rect = getBoundsAt(0); 
      m_lineRect.setRect(rect.x, -LINEWIDTH/2, rect.width, LINEWIDTH); 
      m_isDrawRect = true; 
     } else { 
      Rectangle rect = getBoundsAt(next - 1); 
      m_lineRect.setRect(rect.x, rect.y + rect.height - LINEWIDTH/2, 
        rect.width, LINEWIDTH); 
      m_isDrawRect = true; 
     } 
    } 

    private void initGlassPane(Component c, Point tabPt, int a_tabIndex) { 
     //Point p = (Point) pt.clone(); 
     getRootPane().setGlassPane(s_glassPane); 
     if (hasGhost()) { 
      Rectangle rect = getBoundsAt(a_tabIndex); 
      BufferedImage image = new BufferedImage(c.getWidth(), 
        c.getHeight(), BufferedImage.TYPE_INT_ARGB); 
      Graphics g = image.getGraphics(); 
      c.paint(g); 
      image = image.getSubimage(rect.x, rect.y, rect.width, rect.height); 
      s_glassPane.setImage(image);    
     } // if 

     s_glassPane.setPoint(buildGhostLocation(tabPt)); 
     s_glassPane.setVisible(true); 
    } 

    private Rectangle getTabAreaBound() { 
     Rectangle lastTab = getUI().getTabBounds(this, getTabCount() - 1); 
     return new Rectangle(0, 0, getWidth(), lastTab.y + lastTab.height); 
    } 

    public void paintComponent(Graphics g) { 
     super.paintComponent(g); 

     if (m_isDrawRect) { 
      Graphics2D g2 = (Graphics2D) g; 
      g2.setPaint(m_lineColor); 
      g2.fill(m_lineRect); 
     } // if 
    } 

    public interface TabAcceptor { 
     boolean isDropAcceptable(DnDTabbedPane a_component, int a_index); 
    } 
} 

class GhostGlassPane extends JPanel { 
    public static final long serialVersionUID = 1L; 
    private final AlphaComposite m_composite; 

    private Point m_location = new Point(0, 0); 

    private BufferedImage m_draggingGhost = null; 

    public GhostGlassPane() { 
     setOpaque(false); 
     m_composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f); 
    } 

    public void setImage(BufferedImage draggingGhost) { 
     m_draggingGhost = draggingGhost; 
    } 

    public void setPoint(Point a_location) { 
     m_location.x = a_location.x; 
     m_location.y = a_location.y; 
    } 

    public int getGhostWidth() { 
     if (m_draggingGhost == null) { 
      return 0; 
     } // if 

     return m_draggingGhost.getWidth(this); 
    } 

    public int getGhostHeight() { 
     if (m_draggingGhost == null) { 
      return 0; 
     } // if 

     return m_draggingGhost.getHeight(this); 
    } 

    public void paintComponent(Graphics g) { 
     if (m_draggingGhost == null) { 
      return; 
     } // if 

     Graphics2D g2 = (Graphics2D) g; 
     g2.setComposite(m_composite); 

     g2.drawImage(m_draggingGhost, (int) m_location.getX(), (int) m_location.getY(), null); 
    } 
} 
7

Tìm thấy mã này hiện có trên tubes:

class DnDTabbedPane extends JTabbedPane { 
    private static final int LINEWIDTH = 3; 
    private static final String NAME = "test"; 
    private final GhostGlassPane glassPane = new GhostGlassPane(); 
    private final Rectangle2D lineRect = new Rectangle2D.Double(); 
    private final Color  lineColor = new Color(0, 100, 255); 
    //private final DragSource dragSource = new DragSource(); 
    //private final DropTarget dropTarget; 
    private int dragTabIndex = -1; 

    public DnDTabbedPane() { 
    super(); 
    final DragSourceListener dsl = new DragSourceListener() { 
     public void dragEnter(DragSourceDragEvent e) { 
     e.getDragSourceContext().setCursor(DragSource.DefaultMoveDrop); 
     } 
     public void dragExit(DragSourceEvent e) { 
     e.getDragSourceContext().setCursor(DragSource.DefaultMoveNoDrop); 
     lineRect.setRect(0,0,0,0); 
     glassPane.setPoint(new Point(-1000,-1000)); 
     glassPane.repaint(); 
     } 
     public void dragOver(DragSourceDragEvent e) { 
     //e.getLocation() 
     //This method returns a Point indicating the cursor location in screen coordinates at the moment 
     Point tabPt = e.getLocation(); 
     SwingUtilities.convertPointFromScreen(tabPt, DnDTabbedPane.this); 
     Point glassPt = e.getLocation(); 
     SwingUtilities.convertPointFromScreen(glassPt, glassPane); 
     int targetIdx = getTargetTabIndex(glassPt); 
     if(getTabAreaBound().contains(tabPt) && targetIdx>=0 && 
      targetIdx!=dragTabIndex && targetIdx!=dragTabIndex+1) { 
      e.getDragSourceContext().setCursor(DragSource.DefaultMoveDrop); 
     }else{ 
      e.getDragSourceContext().setCursor(DragSource.DefaultMoveNoDrop); 
     } 
     } 
     public void dragDropEnd(DragSourceDropEvent e) { 
     lineRect.setRect(0,0,0,0); 
     dragTabIndex = -1; 
     if(hasGhost()) { 
      glassPane.setVisible(false); 
      glassPane.setImage(null); 
     } 
     } 
     public void dropActionChanged(DragSourceDragEvent e) {} 
    }; 
    final Transferable t = new Transferable() { 
     private final DataFlavor FLAVOR = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType, NAME); 
     public Object getTransferData(DataFlavor flavor) { 
     return DnDTabbedPane.this; 
     } 
     public DataFlavor[] getTransferDataFlavors() { 
     DataFlavor[] f = new DataFlavor[1]; 
     f[0] = this.FLAVOR; 
     return f; 
     } 
     public boolean isDataFlavorSupported(DataFlavor flavor) { 
     return flavor.getHumanPresentableName().equals(NAME); 
     } 
    }; 
    final DragGestureListener dgl = new DragGestureListener() { 
     public void dragGestureRecognized(DragGestureEvent e) { 
     Point tabPt = e.getDragOrigin(); 
     dragTabIndex = indexAtLocation(tabPt.x, tabPt.y); 
     if(dragTabIndex<0) return; 
     initGlassPane(e.getComponent(), e.getDragOrigin()); 
     try{ 
      e.startDrag(DragSource.DefaultMoveDrop, t, dsl); 
     }catch(InvalidDnDOperationException idoe) { 
      idoe.printStackTrace(); 
     } 
     } 
    }; 
    //dropTarget = 
    new DropTarget(glassPane, DnDConstants.ACTION_COPY_OR_MOVE, new CDropTargetListener(), true); 
    new DragSource().createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY_OR_MOVE, dgl); 
    } 

    class CDropTargetListener implements DropTargetListener{ 
    public void dragEnter(DropTargetDragEvent e) { 
     if(isDragAcceptable(e)) e.acceptDrag(e.getDropAction()); 
     else e.rejectDrag(); 
    } 
    public void dragExit(DropTargetEvent e) {} 
    public void dropActionChanged(DropTargetDragEvent e) {} 
    public void dragOver(final DropTargetDragEvent e) { 
     if(getTabPlacement()==JTabbedPane.TOP || getTabPlacement()==JTabbedPane.BOTTOM) { 
     initTargetLeftRightLine(getTargetTabIndex(e.getLocation())); 
     }else{ 
     initTargetTopBottomLine(getTargetTabIndex(e.getLocation())); 
     } 
     repaint(); 
     if(hasGhost()) { 
     glassPane.setPoint(e.getLocation()); 
     glassPane.repaint(); 
     } 
    } 

    public void drop(DropTargetDropEvent e) { 
     if(isDropAcceptable(e)) { 
     convertTab(dragTabIndex, getTargetTabIndex(e.getLocation())); 
     e.dropComplete(true); 
     }else{ 
     e.dropComplete(false); 
     } 
     repaint(); 
    } 
    public boolean isDragAcceptable(DropTargetDragEvent e) { 
     Transferable t = e.getTransferable(); 
     if(t==null) return false; 
     DataFlavor[] f = e.getCurrentDataFlavors(); 
     if(t.isDataFlavorSupported(f[0]) && dragTabIndex>=0) { 
     return true; 
     } 
     return false; 
    } 
    public boolean isDropAcceptable(DropTargetDropEvent e) { 
     Transferable t = e.getTransferable(); 
     if(t==null) return false; 
     DataFlavor[] f = t.getTransferDataFlavors(); 
     if(t.isDataFlavorSupported(f[0]) && dragTabIndex>=0) { 
     return true; 
     } 
     return false; 
    } 
    } 

    private boolean hasGhost = true; 
    public void setPaintGhost(boolean flag) { 
    hasGhost = flag; 
    } 
    public boolean hasGhost() { 
    return hasGhost; 
    } 
    private int getTargetTabIndex(Point glassPt) { 
    Point tabPt = SwingUtilities.convertPoint(glassPane, glassPt, DnDTabbedPane.this); 
    boolean isTB = getTabPlacement()==JTabbedPane.TOP || getTabPlacement()==JTabbedPane.BOTTOM; 
    for(int i=0;i<getTabCount();i++) { 
     Rectangle r = getBoundsAt(i); 
     if(isTB) r.setRect(r.x-r.width/2, r.y, r.width, r.height); 
     else r.setRect(r.x, r.y-r.height/2, r.width, r.height); 
     if(r.contains(tabPt)) return i; 
    } 
    Rectangle r = getBoundsAt(getTabCount()-1); 
    if(isTB) r.setRect(r.x+r.width/2, r.y, r.width, r.height); 
    else r.setRect(r.x, r.y+r.height/2, r.width, r.height); 
    return r.contains(tabPt)?getTabCount():-1; 
    } 
    private void convertTab(int prev, int next) { 
    if(next<0 || prev==next) { 
     //System.out.println("press="+prev+" next="+next); 
     return; 
    } 
    Component cmp = getComponentAt(prev); 
    String str = getTitleAt(prev); 
    if(next==getTabCount()) { 
     //System.out.println("last: press="+prev+" next="+next); 
     remove(prev); 
     addTab(str, cmp); 
     setSelectedIndex(getTabCount()-1); 
    }else if(prev>next) { 
     //System.out.println(" >: press="+prev+" next="+next); 
     remove(prev); 
     insertTab(str, null, cmp, null, next); 
     setSelectedIndex(next); 
    }else{ 
     //System.out.println(" <: press="+prev+" next="+next); 
     remove(prev); 
     insertTab(str, null, cmp, null, next-1); 
     setSelectedIndex(next-1); 
    } 
    } 

    private void initTargetLeftRightLine(int next) { 
    if(next<0 || dragTabIndex==next || next-dragTabIndex==1) { 
     lineRect.setRect(0,0,0,0); 
    }else if(next==getTabCount()) { 
     Rectangle rect = getBoundsAt(getTabCount()-1); 
     lineRect.setRect(rect.x+rect.width-LINEWIDTH/2,rect.y,LINEWIDTH,rect.height); 
    }else if(next==0) { 
     Rectangle rect = getBoundsAt(0); 
     lineRect.setRect(-LINEWIDTH/2,rect.y,LINEWIDTH,rect.height); 
    }else{ 
     Rectangle rect = getBoundsAt(next-1); 
     lineRect.setRect(rect.x+rect.width-LINEWIDTH/2,rect.y,LINEWIDTH,rect.height); 
    } 
    } 
    private void initTargetTopBottomLine(int next) { 
    if(next<0 || dragTabIndex==next || next-dragTabIndex==1) { 
     lineRect.setRect(0,0,0,0); 
    }else if(next==getTabCount()) { 
     Rectangle rect = getBoundsAt(getTabCount()-1); 
     lineRect.setRect(rect.x,rect.y+rect.height-LINEWIDTH/2,rect.width,LINEWIDTH); 
    }else if(next==0) { 
     Rectangle rect = getBoundsAt(0); 
     lineRect.setRect(rect.x,-LINEWIDTH/2,rect.width,LINEWIDTH); 
    }else{ 
     Rectangle rect = getBoundsAt(next-1); 
     lineRect.setRect(rect.x,rect.y+rect.height-LINEWIDTH/2,rect.width,LINEWIDTH); 
    } 
    } 

    private void initGlassPane(Component c, Point tabPt) { 
    //Point p = (Point) pt.clone(); 
    getRootPane().setGlassPane(glassPane); 
    if(hasGhost()) { 
     Rectangle rect = getBoundsAt(dragTabIndex); 
     BufferedImage image = new BufferedImage(c.getWidth(), c.getHeight(), BufferedImage.TYPE_INT_ARGB); 
     Graphics g = image.getGraphics(); 
     c.paint(g); 
     image = image.getSubimage(rect.x,rect.y,rect.width,rect.height); 
     glassPane.setImage(image); 
    } 
    Point glassPt = SwingUtilities.convertPoint(c, tabPt, glassPane); 
    glassPane.setPoint(glassPt); 
    glassPane.setVisible(true); 
    } 

    private Rectangle getTabAreaBound() { 
    Rectangle lastTab = getUI().getTabBounds(this, getTabCount()-1); 
    return new Rectangle(0,0,getWidth(),lastTab.y+lastTab.height); 
    } 

    public void paintComponent(Graphics g) { 
    super.paintComponent(g); 
    if(dragTabIndex>=0) { 
     Graphics2D g2 = (Graphics2D)g; 
     g2.setPaint(lineColor); 
     g2.fill(lineRect); 
    } 
    } 
} 

class GhostGlassPane extends JPanel { 
    private final AlphaComposite composite; 
    private Point location = new Point(0, 0); 
    private BufferedImage draggingGhost = null; 
    public GhostGlassPane() { 
    setOpaque(false); 
    composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f); 
    } 
    public void setImage(BufferedImage draggingGhost) { 
    this.draggingGhost = draggingGhost; 
    } 
    public void setPoint(Point location) { 
    this.location = location; 
    } 
    public void paintComponent(Graphics g) { 
    if(draggingGhost == null) return; 
    Graphics2D g2 = (Graphics2D) g; 
    g2.setComposite(composite); 
    double xx = location.getX() - (draggingGhost.getWidth(this) /2d); 
    double yy = location.getY() - (draggingGhost.getHeight(this)/2d); 
    g2.drawImage(draggingGhost, (int)xx, (int)yy , null); 
    } 
} 
+0

Tôi thực sự biết về việc này, và tôi đã tò mò về lựa chọn thay thế. Bây giờ, tôi sẽ chấp nhận câu trả lời của bạn. –

27

Curses! Bị đánh vào cú đấm bởi tìm kiếm của Google. Thật không may, thật không có cách nào dễ dàng để tạo các tab tab có thể kéo (hoặc bất kỳ thành phần nào khác) trong Swing. Vì vậy, trong khi ví dụ ở trên là hoàn thành này tôi đã viết là một chút đơn giản. Vì vậy, nó hy vọng sẽ chứng minh các kỹ thuật tiên tiến hơn liên quan đến một chút rõ ràng hơn. Các bước thực hiện:

  1. Phát hiện rằng một kéo đã xảy ra
  2. Vẽ tab kéo vào một bộ đệm offscreen
  3. Theo dõi vị trí chuột trong khi kéo xảy ra
  4. Vẽ tab trong bộ đệm trên đỉnh thành phần.

Ví dụ trên sẽ cung cấp cho bạn những gì bạn muốn nhưng nếu bạn thực sự hiểu các kỹ thuật được áp dụng ở đây, có thể là một bài tập tốt hơn để làm tròn các cạnh của ví dụ này và thêm các tính năng bổ sung được minh họa ở trên.

Hoặc có thể tôi chỉ thất vọng vì tôi đã dành thời gian để viết giải pháp này khi một đã tồn tại: p

import java.awt.Component; 
import java.awt.Graphics; 
import java.awt.Image; 
import java.awt.Point; 
import java.awt.Rectangle; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseMotionAdapter; 
import java.awt.image.BufferedImage; 

import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JTabbedPane; 


public class DraggableTabbedPane extends JTabbedPane { 

    private boolean dragging = false; 
    private Image tabImage = null; 
    private Point currentMouseLocation = null; 
    private int draggedTabIndex = 0; 

    public DraggableTabbedPane() { 
    super(); 
    addMouseMotionListener(new MouseMotionAdapter() { 
     public void mouseDragged(MouseEvent e) { 

     if(!dragging) { 
      // Gets the tab index based on the mouse position 
      int tabNumber = getUI().tabForCoordinate(DraggableTabbedPane.this, e.getX(), e.getY()); 

      if(tabNumber >= 0) { 
      draggedTabIndex = tabNumber; 
      Rectangle bounds = getUI().getTabBounds(DraggableTabbedPane.this, tabNumber); 


      // Paint the tabbed pane to a buffer 
      Image totalImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB); 
      Graphics totalGraphics = totalImage.getGraphics(); 
      totalGraphics.setClip(bounds); 
      // Don't be double buffered when painting to a static image. 
      setDoubleBuffered(false); 
      paintComponent(totalGraphics); 

      // Paint just the dragged tab to the buffer 
      tabImage = new BufferedImage(bounds.width, bounds.height, BufferedImage.TYPE_INT_ARGB); 
      Graphics graphics = tabImage.getGraphics(); 
      graphics.drawImage(totalImage, 0, 0, bounds.width, bounds.height, bounds.x, bounds.y, bounds.x + bounds.width, bounds.y+bounds.height, DraggableTabbedPane.this); 

      dragging = true; 
      repaint(); 
      } 
     } else { 
      currentMouseLocation = e.getPoint(); 

      // Need to repaint 
      repaint(); 
     } 

     super.mouseDragged(e); 
     } 
    }); 

    addMouseListener(new MouseAdapter() { 
     public void mouseReleased(MouseEvent e) { 

     if(dragging) { 
      int tabNumber = getUI().tabForCoordinate(DraggableTabbedPane.this, e.getX(), 10); 

      if(tabNumber >= 0) { 
      Component comp = getComponentAt(draggedTabIndex); 
      String title = getTitleAt(draggedTabIndex); 
      removeTabAt(draggedTabIndex); 
      insertTab(title, null, comp, null, tabNumber); 
      } 
     } 

     dragging = false; 
     tabImage = null; 
     } 
    }); 
    } 

    protected void paintComponent(Graphics g) { 
    super.paintComponent(g); 

    // Are we dragging? 
    if(dragging && currentMouseLocation != null && tabImage != null) { 
     // Draw the dragged tab 
     g.drawImage(tabImage, currentMouseLocation.x, currentMouseLocation.y, this); 
    } 
    } 

    public static void main(String[] args) { 
    JFrame test = new JFrame("Tab test"); 
    test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    test.setSize(400, 400); 

    DraggableTabbedPane tabs = new DraggableTabbedPane(); 
    tabs.addTab("One", new JButton("One")); 
    tabs.addTab("Two", new JButton("Two")); 
    tabs.addTab("Three", new JButton("Three")); 
    tabs.addTab("Four", new JButton("Four")); 

    test.add(tabs); 
    test.setVisible(true); 
    } 
} 
+0

+1! Nó hoạt động, nhưng đó là một chút lỗi. Nếu bạn kéo tab quá nó sẽ gây ra một mớ hỗn độn. –

6

@Tony: Có vẻ như Euguenes solution vừa xem vừa bảo quản TabComponents trong khi hoán đổi.

Phương thức convertTab chỉ cần nhớ TabComponent và đặt nó vào tab mới mà nó tạo.

Hãy thử sử dụng này:

private void convertTab(TabTransferData a_data, int a_targetIndex) { 

      DnDTabbedPane source = a_data.getTabbedPane(); 
      System.out.println("this=source? " + (this == source)); 
      int sourceIndex = a_data.getTabIndex(); 
      if (sourceIndex < 0) { 
        return; 
      } // if 
      //Save the tab's component, title, and TabComponent. 
      Component cmp = source.getComponentAt(sourceIndex); 
      String str = source.getTitleAt(sourceIndex); 
      Component tcmp = source.getTabComponentAt(sourceIndex); 

      if (this != source) { 
        source.remove(sourceIndex); 

        if (a_targetIndex == getTabCount()) { 
          addTab(str, cmp); 
          setTabComponentAt(getTabCount()-1, tcmp); 
        } else { 
          if (a_targetIndex < 0) { 
            a_targetIndex = 0; 
          } // if 

          insertTab(str, null, cmp, null, a_targetIndex); 
          setTabComponentAt(a_targetIndex, tcmp); 
        } // if 

        setSelectedComponent(cmp); 
        return; 
      } // if 
      if (a_targetIndex < 0 || sourceIndex == a_targetIndex) { 
        return; 
      } // if 
      if (a_targetIndex == getTabCount()) {  
        source.remove(sourceIndex); 
        addTab(str, cmp); 
        setTabComponentAt(getTabCount() - 1, tcmp); 
        setSelectedIndex(getTabCount() - 1); 
      } else if (sourceIndex > a_targetIndex) { 
        source.remove(sourceIndex); 
        insertTab(str, null, cmp, null, a_targetIndex); 
        setTabComponentAt(a_targetIndex, tcmp); 
        setSelectedIndex(a_targetIndex); 
      } else { 
        source.remove(sourceIndex); 
        insertTab(str, null, cmp, null, a_targetIndex - 1); 
        setTabComponentAt(a_targetIndex - 1, tcmp); 
        setSelectedIndex(a_targetIndex - 1); 
      } 

    } 
2

Thêm phần này vào isDragAcceptable để tránh trường hợp ngoại lệ:

boolean transferDataFlavorFound = false; 
for (DataFlavor transferDataFlavor : t.getTransferDataFlavors()) { 
    if (FLAVOR.equals(transferDataFlavor)) { 
     transferDataFlavorFound = true; 
     break; 
    } 
} 
if (transferDataFlavorFound == false) { 
    return false; 
} 
Các vấn đề liên quan