Swing/DnDExportTabbedPane のバックアップの現在との差分(No.18)
TITLE:JTabbedPane間でタブのドラッグ&ドロップ移動
Posted by aterai at 2009-03-23
JTabbedPane間でタブのドラッグ&ドロップ移動
JTabbedPane間でタブのDrag&Dropによる移動を行います。-
category: swing
folder: DnDExportTabbedPane
title: JTabbedPane間でタブのドラッグ&ドロップ移動
tags: [JTabbedPane, TransferHandler, DragAndDrop, GlassPane, Cursor]
author: aterai
pubdate: 2009-03-23T14:24:48+09:00
description: JTabbedPane間でタブのDrag&Dropによる移動を行います。
image:
hreflang:
href: https://java-swing-tips.blogspot.com/2010/02/tabtransferhandler.html lang: en
概要
JTabbedPane
間でタブのDrag&Drop
による移動を行います。
- &jnlp;
- &jar;
- &zip;
Screenshot
Advertisement
サンプルコード
#spanend
#spanadd
* サンプルコード [#sourcecode]
#spanend
#spanadd
#code(link){{
#spanend
class TabTransferHandler extends TransferHandler {
private final DataFlavor localObjectFlavor;
public TabTransferHandler() {
System.out.println("TabTransferHandler");
localObjectFlavor = new ActivationDataFlavor(
DnDTabbedPane.class, DataFlavor.javaJVMLocalObjectMimeType, "DnDTabbedPane");
}
//private static DnDTabbedPane source;
//private synchronized static void setComponent(JComponent comp) {
// if(comp instanceof DnDTabbedPane) {
// source = (DnDTabbedPane)comp;
// }
//}
//@Override public void exportAsDrag(JComponent comp, InputEvent e, int action) {
// super.exportAsDrag(comp, e, action);
// setComponent(comp);
//}
private final DataFlavor localObjectFlavor = new DataFlavor(DnDTabData.class, "DnDTabData");
private DnDTabbedPane source = null;
#spanadd
#spanend
@Override protected Transferable createTransferable(JComponent c) {
System.out.println("createTransferable");
if(c instanceof DnDTabbedPane) source = (DnDTabbedPane)c;
return new DataHandler(c, localObjectFlavor.getMimeType());
if (c instanceof DnDTabbedPane) source = (DnDTabbedPane) c;
return new Transferable() {
@Override public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[] {localObjectFlavor};
}
#spanadd
#spanend
@Override public boolean isDataFlavorSupported(DataFlavor flavor) {
return Objects.equals(localObjectFlavor, flavor);
}
#spanadd
#spanend
@Override public Object getTransferData(DataFlavor flavor)
throws UnsupportedFlavorException, IOException {
if (isDataFlavorSupported(flavor)) {
return new DnDTabData(source);
} else {
throw new UnsupportedFlavorException(flavor);
}
}
};
}
#spanadd
#spanend
@Override public boolean canImport(TransferSupport support) {
//System.out.println("canImport");
// System.out.println("canImport");
if (!support.isDrop() || !support.isDataFlavorSupported(localObjectFlavor)) {
return false;
}
support.setDropAction(MOVE);
support.setDropAction(TransferHandler.MOVE);
DropLocation tdl = support.getDropLocation();
Point pt = tdl.getDropPoint();
DnDTabbedPane target = (DnDTabbedPane)support.getComponent();
DnDTabbedPane target = (DnDTabbedPane) support.getComponent();
target.autoScrollTest(pt);
DnDTabbedPane.DropLocation dl =
(DnDTabbedPane.DropLocation)target.dropLocationForPoint(pt);
(DnDTabbedPane.DropLocation) target.dropLocationForPoint(pt);
int idx = dl.getIndex();
boolean isDropable = false;
boolean isDroppable = false;
if (target==source) {
isDropable = target.getTabAreaBounds().contains(pt) && idx>=0 &&
idx!=target.dragTabIndex && idx!=target.dragTabIndex+1;
if (target == source) {
isDroppable = target.getTabAreaBounds().contains(pt) && idx >= 0 &&
idx != target.dragTabIndex && idx != target.dragTabIndex + 1;
} else {
if (source!=null && target!=source.getComponentAt(source.dragTabIndex)) {
isDropable = target.getTabAreaBounds().contains(pt) && idx>=0;
if (source != null && target != source.getComponentAt(source.dragTabIndex)) {
isDroppable = target.getTabAreaBounds().contains(pt) && idx >= 0;
}
}
Component c = target.getRootPane().getGlassPane();
c.setCursor(isDropable?DragSource.DefaultMoveDrop:DragSource.DefaultMoveNoDrop);
if (isDropable) {
c.setCursor(isDroppable?DragSource.DefaultMoveDrop:DragSource.DefaultMoveNoDrop);
if (isDroppable) {
support.setShowDropLocation(true);
dl.setDropable(true);
dl.setDroppable(true);
target.setDropLocation(dl, null, true);
return true;
} else {
support.setShowDropLocation(false);
dl.setDropable(false);
dl.setDroppable(false);
target.setDropLocation(dl, null, false);
return false;
}
}
private BufferedImage makeDragTabImage(DnDTabbedPane tabbedPane) {
Rectangle rect = tabbedPane.getBoundsAt(tabbedPane.dragTabIndex);
BufferedImage image = new BufferedImage(
tabbedPane.getWidth(), tabbedPane.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
tabbedPane.paint(g);
g.dispose();
if (rect.x<0) {
rect.translate(-rect.x,0);
if (rect.x < 0) {
rect.translate(-rect.x, 0);
}
if (rect.y<0) {
rect.translate(0,-rect.y);
if (rect.y < 0) {
rect.translate(0, -rect.y);
}
if (rect.x+rect.width>image.getWidth()) {
if (rect.x + rect.width > image.getWidth()) {
rect.width = image.getWidth() - rect.x;
}
if (rect.y+rect.height>image.getHeight()) {
if (rect.y + rect.height > image.getHeight()) {
rect.height = image.getHeight() - rect.y;
}
return image.getSubimage(rect.x,rect.y,rect.width,rect.height);
return image.getSubimage(rect.x, rect.y, rect.width, rect.height);
}
private static GhostGlassPane glassPane;
@Override public int getSourceActions(JComponent c) {
System.out.println("getSourceActions");
DnDTabbedPane src = (DnDTabbedPane)c;
if (glassPane==null) {
c.getRootPane().setGlassPane(glassPane = new GhostGlassPane(src));
if (c instanceof DnDTabbedPane) {
DnDTabbedPane src = (DnDTabbedPane) c;
c.getRootPane().setGlassPane(new GhostGlassPane(src));
if (src.dragTabIndex < 0) {
return TransferHandler.NONE;
}
setDragImage(makeDragTabImage(src));
c.getRootPane().getGlassPane().setVisible(true);
return TransferHandler.MOVE;
}
if (src.dragTabIndex<0) return NONE;
glassPane.setImage(makeDragTabImage(src));
source = src;
//setDragImage(img); //java 1.7.0-ea-b84
glassPane.setVisible(true);
return MOVE;
return TransferHandler.NONE;
}
#spanadd
#spanend
@Override public boolean importData(TransferSupport support) {
System.out.println("importData");
if (!canImport(support)) return false;
DnDTabbedPane target = (DnDTabbedPane)support.getComponent();
DnDTabbedPane target = (DnDTabbedPane) support.getComponent();
DnDTabbedPane.DropLocation dl = target.getDropLocation();
try {
DnDTabbedPane source = (DnDTabbedPane)support.getTransferable()
DnDTabbedPane source = (DnDTabbedPane) support.getTransferable()
.getTransferData(localObjectFlavor);
int index = dl.getIndex(); //boolean insert = dl.isInsert();
if (target==source) {
if (target == source) {
source.convertTab(source.dragTabIndex, index);
} else {
source.exportTab(source.dragTabIndex, target, index);
}
return true;
} catch (UnsupportedFlavorException ufe) {
ufe.printStackTrace();
} catch (java.io.IOException ioe) {
} catch (IOException ioe) {
ioe.printStackTrace();
}
return false;
}
#spanadd
#spanend
@Override protected void exportDone(JComponent c, Transferable data, int action) {
System.out.println("exportDone");
DnDTabbedPane src = (DnDTabbedPane)c;
DnDTabbedPane src = (DnDTabbedPane) c;
c.getRootPane().getGlassPane().setVisible(false);
src.setDropLocation(null, null, false);
}
}
解説
上記のサンプルでは、JDK 6 で導入された、TransferHandler.DropLocationを継承するDnDTabbedPane.DropLocationなどを作成して、JTabbedPane間でタブの移動ができるように設定しています。解説
上記のサンプルでは、JDK 6
で導入された、TransferHandler.DropLocation
を継承するDnDTabbedPane.DropLocation
などを作成して、JTabbedPane
間でタブの移動ができるように設定しています。
- 注意点
- 自身の子であるJTabbedPaneにタブを移動することはできない
- 子コンポーネントがnull(例えばaddTab("Tab",null))のタブは移動不可
- タブが選択不可(例えばsetEnabledAt(idx, false))の場合は移動不可
- バグ?
子コンポーネントがJTableの場合、マウスカーソルが点滅するWindows環境のみ?
- 子コンポーネントがJTextAreaなどの場合、ドラッグ中のタブゴーストが表示できない
JTable、JTextAreaどちらも、JScrollPaneが影響している?- java 1.7.0-ea-b84 で、TransferHandler#setDragImage(Image) を使用するとちゃんと表示される
- textArea.setTransferHandler(null);とすれば、1.6.0でも正常に表示される。
- SCROLL_TAB_LAYOUTの場合、タブゴーストにスクロールボタンが表示される場合がある
- 注意点
- 自身の子として配置されている
JTabbedPane
にタブを移動することはできない - 子コンポーネントが
null
(例えばaddTab("Tab",null)
)のタブは移動不可 - タブが選択不可(例えば
setEnabledAt(idx, false)
)の場合は移動不可
- 自身の子として配置されている
- バグ?
-
子コンポーネントがJTable
の場合、マウスカーソルが点滅する-
Windows
環境のみ?
-
- 子コンポーネントが
JTextArea
などの場合、ドラッグ中のタブゴーストが表示できない-
JTable
、JTextArea
どちらもJScrollPane
が影響している? Java 1.7.0-ea-b84
以上で、TransferHandler#setDragImage(Image)
を使用すると正常に表示される-
textArea.setTransferHandler(null);
とすれば、1.6.0
でも正常に表示される
-
-
SCROLL_TAB_LAYOUT
の場合、タブゴーストにスクロールボタンが表示される場合がある
-
- 注意点
参考リンク
コメント
- タブのドラッグ中、JTable上などでCursorが点滅するのを修正。 -- aterai
- 点滅の原因は? -- Dad?
- おそらく、Cursor flickering during D&D when using CellRendererPane with validationが原因。現在は、canImport メソッド内で、一々GlassPane#setCursor(isDropable?DragSource.DefaultMoveDrop:DragSource.DefaultMoveNoDrop);として回避中。 -- aterai
- 6u20ぐらいからWebStartで、java.security.AccessControlException: access denied (java.awt.AWTPermission accessClipboard)? -- aterai
- チュートリアルのデモDemo - DropDemo (The Java™ Tutorials > Creating a GUI With JFC/Swing Drag and Drop and Data Transfer)でも同様のエラーが発生するので多分Java 1.6.0_??のバグ。 -- aterai
- 6u21では、修正されている?: 6945178 2-High Defect SecurityException upon drag-and-drop(Bug/RFE fixed in JDK 6u21 build) -- aterai
- 修正されたようです。Java SE 6 Update 21 Bug Fixes -- aterai
- getTabPlacement()==RIGHTなどの場合に、DropTargetの描画がおかしくなるのを修正。 -- aterai