Swing/DragDropEndNewFrame のバックアップ(No.4)
- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- 現在との差分 - Visual を表示
- ソース を表示
- Swing/DragDropEndNewFrame へ行く。
- 1 (2022-02-14 (月) 02:17:51)
- 2 (2022-02-14 (月) 20:14:50)
- 3 (2022-02-28 (月) 15:19:34)
- 4 (2024-06-03 (月) 11:49:18)
- category: swing
folder: DragDropEndNewFrame
title: JTabbedPaneのタブがフレーム外にドロップされたら新規JFrameを作成する
tags: [JTabbedPane, DragAndDrop, JFrame]
author: aterai
pubdate: 2022-02-14T02:16:38+09:00
description: JTabbedPaneのタブをドラッグしてフレーム外にドロップされたら新規JFrameとそのタブを配置したJTabbedPaneを作成します。
image: https://drive.google.com/uc?id=1q7P74R90Zr4SF7HSk3SnhVhHaj5tap4P
hreflang:
href: https://java-swing-tips.blogspot.com/2022/02/create-new-jframe-when-jtabbedpane-tab.html lang: en
概要
JTabbedPane
のタブをドラッグしてフレーム外にドロップされたら新規JFrame
とそのタブを配置したJTabbedPane
を作成します。
Screenshot
Advertisement
サンプルコード
class TabDragSourceListener implements DragSourceListener {
@Override public void dragEnter(DragSourceDragEvent e) {
e.getDragSourceContext().setCursor(DragSource.DefaultMoveDrop);
}
@Override public void dragExit(DragSourceEvent e) {
e.getDragSourceContext().setCursor(DragSource.DefaultMoveNoDrop);
}
@Override public void dragDropEnd(DragSourceDropEvent e) {
Component c = e.getDragSourceContext().getComponent();
JRootPane root = ((JComponent) c).getRootPane();
Class<GhostGlassPane> clz = GhostGlassPane.class;
Optional.ofNullable(root.getGlassPane())
.filter(clz::isInstance).map(clz::cast)
.ifPresent(p -> p.setVisible(false));
boolean dropSuccess = e.getDropSuccess();
Window w = SwingUtilities.getWindowAncestor(c);
boolean outOfFrame = !w.getBounds().contains(e.getLocation());
if (dropSuccess && outOfFrame && c instanceof DnDTabbedPane) {
DnDTabbedPane src = (DnDTabbedPane) c;
int index = src.dragTabIndex;
final Component cmp = src.getComponentAt(index);
final Component tab = src.getTabComponentAt(index);
final String title = src.getTitleAt(index);
final Icon icon = src.getIconAt(index);
final String tip = src.getToolTipTextAt(index);
src.remove(index);
DnDTabbedPane tabs = new DnDTabbedPane();
tabs.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
tabs.addTab(title, icon, cmp, tip);
tabs.setTabComponentAt(0, tab);
JFrame frame = new JFrame();
frame.getContentPane().add(tabs);
frame.setSize(320, 240);
frame.setLocation(e.getLocation());
frame.setVisible(true);
}
}
@Override public void dropActionChanged(DragSourceDragEvent e) {
/* not needed */
}
@Override public void dragOver(DragSourceDragEvent e) {
/* not needed */
}
}
View in GitHub: Java, Kotlin解説
DragSourceListener#dragDropEnd(DragSourceDropEvent e)
をオーバーライドしてタブのドロップが終了したとき、その位置がJTabbedPane
の親JFrame
の範囲外の場合新規にJFrame
とJTabbedPane
を作成しタブの中身を移動する- ESCキーやマウスの右クリックによるドロップのキャンセルに対応するため、
MimeType
がDataFlavor.javaJVMLocalObjectMimeType
のDataFlavor
だけではなくファイルリスト対応のDataFlavor.javaFileListFlavor
もドロップ可能に設定し、親JFrame
にタブがドロップされたら空ファイルリストをコピー(空なので実際は何もコピーしない)してドロップが成功したと見せかけている- 空ファイルリストをコピーでドロップが成功したら新規
JFrame
を作成してタブをコピーし、ドラッグ元からタブを削除 - ドラッグ中にESCキーなどでドロップがキャンセルされたら
DragSourceDropEvent#getDropSuccess()
がfalse
になるので、この場合は何もせずにドラッグ終了
- 空ファイルリストをコピーでドロップが成功したら新規
- タブのドロップ先のアプリケーションが空ファイルのドロップに対応している場合、そのアプリケーションが新規
JFrame
より手前に表示されることがある - ファイルのドロップが不可のアプリケーション上では新規
JFrame
を作成できない