Как реализовать перетаскиваемую вкладку с помощью Java Swing?

Как реализовать перетаскиваемую вкладку с помощью Java Swing? Вместо статической JTabbedPane я бы хотел перетащить вкладку в другое положение, чтобы переставить вкладки.

EDIT : Учебники Java – drag and drop и передача данных .

Проклятия! Избили в результате поиска Google. К сожалению, в Swing нет простого способа создания перетаскиваемых панелей вкладок (или любых других компонентов). Таким образом, пока приведенный выше пример завершен, этот, который я только что написал, немного проще. Таким образом, мы надеемся, что более совершенные методы будут немного более ясными. Шаги:

  1. Обнаружить, что произошло drag and drop
  2. Нарисуйте перетаскиваемую вкладку в буфер вне экрана
  3. Отслеживание положения мыши во время перетаскивания
  4. Нарисуйте вкладку в буфере поверх компонента.

Вышеприведенный пример даст вам то, что вы хотите, но если вы хотите по-настоящему понять методы, применяемые здесь, это может быть лучшим упражнением, чтобы округлить края этого примера и добавить дополнительные функции, показанные выше.

Или, может быть, я просто разочарован, потому что я потратил время на это решение, когда он уже существовал: 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); } } 

Мне понравилась песня Terai Atsuhiro san DnDTabbedPane , но мне хотелось большего от нее. Первоначальная реализация Terai перенесла вкладки в TabbedPane, но было бы лучше, если бы я мог перетащить с одной TabbedPane на другую.

Вдохновленный усилиями Тома , я решил сам изменить код. Есть некоторые детали, которые я добавил. Например, вкладка-призрак теперь скользит вдоль области с вкладками вместо перемещения вместе с мышью.

setAcceptor(TabAcceptor a_acceptor) должен позволить потребительскому коду решить, следует ли переводить одну вкладку из одной вкладки в другую. Акцептор по умолчанию всегда возвращает значение 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(rx - r.width / 2, ry, r.width, r.height); } else { r.setRect(rx, ry - 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 = rx + r.width / 2; r.setRect(x, ry, getWidth() - x, r.height); } else { int y = ry + r.height / 2; r.setRect(rx, 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); } } 

Нашел этот код там на трубах :

 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: 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); } } 

@Tony: Похоже, решение Euguenes просто не учитывает сохранение TabComponents во время обмена.

Метод convertTab просто должен помнить TabComponent и устанавливать его на новые вкладки, которые он делает.

Попробуйте использовать это:

  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); } } 

Добавьте это в isDragAcceptable, чтобы избежать исключений:

 boolean transferDataFlavorFound = false; for (DataFlavor transferDataFlavor : t.getTransferDataFlavors()) { if (FLAVOR.equals(transferDataFlavor)) { transferDataFlavorFound = true; break; } } if (transferDataFlavorFound == false) { return false; } 
  • Как создать графический интерфейс пользователя на C ++?
  • как изменить пользовательский интерфейс в зависимости от выбора поля со списком
  • Установка свойства Style метки WPF в коде?
  • Как отобразить текущее значение предпочтения Android в сводке предпочтений?
  • Swing vs JavaFx для настольных приложений
  • установить и отключить иконки JToggleButton
  • Как добавить дополнительную кнопку в строку заголовка windows?
  • Почему большинство пользовательских интерфейсов однопоточных?
  • Установить альфа / непрозрачность макета
  • Темный прозрачный слой над QMainWindow в Qt
  • paintComponent () vs paint () и JPanel vs Canvas в графическом интерфейсе типа кисти
  • Interesting Posts

    Numpy to TFrecords: есть ли более простой способ обработки пакетных входов из tfrecords?

    Можно ли реализовать гладкую прокрутку в виде списка WPF?

    Windows 7 Alt + Tab прозрачная оконная задержка

    Для чего используется функция id ()?

    Как легко использовать расширенные параметры поиска Windows 7?

    Как создать видеоклип из сегментов существующего файла AVI?

    Как я могу сделать скриншоты ПК до того, как он загрузится?

    Неправильная специализированная функция генерируется в Swift 3 по косвенному вызову

    Проблема с отображением в «новых» программах Microsoft в Windows 7

    C Программирование: malloc () внутри другой функции

    MongoDB ‘count ()’ очень медленный. Как мы усовершенствуем / работаем с ним?

    Как упаковать переносимую библиотеку .NET, ориентированную на .NET Core?

    Как преобразовать XML в java.util.Map и наоборот

    Шрифт гиперссылки в Excel всегда изменяется на шрифт / размер шрифта по умолчанию

    Лучшее использование HandlerThread над другими подобными classами

    Давайте будем гением компьютера.