JTextComponentにファイルとテキストをドロップ可能に設定する
Total: 1015
, Today: 2
, Yesterday: 1
Posted by aterai at
Last-modified:
概要
JTextComponent
にデフォルトの文字列だけでなくファイルもドロップ可能になるようなTransferHandler
を設定します。
Screenshot
Advertisement
サンプルコード
public void addTab(File file) {
JTextArea textArea = new JTextArea();
textArea.setDragEnabled(true);
new DropTarget(textArea, DnDConstants.ACTION_COPY,
new FileDropTargetListener(), true);
if (file != null) {
try (Reader in = Files.newBufferedReader(
file.toPath(), StandardCharsets.UTF_8)) {
textArea.read(in, "File");
tabbedPane.addTab(file.getName(), new JScrollPane(textArea));
} catch (IOException ex) {
UIManager.getLookAndFeel().provideErrorFeedback(textArea);
}
} else {
tabbedPane.addTab("*untitled*", new JScrollPane(textArea));
}
tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1);
}
public void addFile(Transferable transferable)
throws UnsupportedFlavorException, IOException {
List<?> list = (List<?>) transferable.getTransferData(
DataFlavor.javaFileListFlavor);
new SwingWorker<Void, Void>() {
@Override protected Void doInBackground() {
for (Object o : list) {
if (o instanceof File) {
addTab((File) o);
}
}
return null;
}
}.execute();
}
private class FileDropTargetListener extends DropTargetAdapter {
@Override public void drop(DropTargetDropEvent e) {
Transferable transferable = e.getTransferable();
if (e.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
e.acceptDrop(DnDConstants.ACTION_COPY);
try {
addFile(transferable);
e.dropComplete(true);
} catch (UnsupportedFlavorException | IOException ex) {
e.dropComplete(false);
}
} else {
JTextComponent textArea = (JTextComponent) e.getSource();
TransferHandler textHandler = textArea.getTransferHandler();
if (textHandler != null) {
textHandler.importData(textArea, transferable);
}
}
}
}
private class FileTransferHandler extends TransferHandler {
@Override public boolean canImport(TransferSupport support) {
boolean isDrop = support.isDrop();
boolean supported = support.isDataFlavorSupported(
DataFlavor.javaFileListFlavor);
return supported && isDrop;
}
@Override public boolean importData(TransferSupport support) {
Transferable transferable = support.getTransferable();
try {
addFile(transferable);
return true;
} catch (IOException | UnsupportedFlavorException ex) {
return false;
}
}
}
View in GitHub: Java, Kotlin解説
FileTransferHandler
を設定したJFrame
- 子コンポーネントやタイトルバーを含む領域にファイルをドロップ可能
Window window = SwingUtilities.getWindowAncestor(tabbedPane); if (window instanceof JFrame) { ((JFrame) window).setTransferHandler(new FileTransferHandler()); }
- 子コンポーネントやタイトルバーを含む領域にファイルをドロップ可能
- デフォルトの
JTextArea
BasicTextUI.TextTransferHandler
がデフォルトで設定されているのでテキスト文字列を別コンポーネントなどからドロップ(ペースト)可能だが、親JFrame
に設定したFileTransferHandler
はこのBasicTextUI.TextTransferHandler
に打ち消されるためファイルのドロップは不可JTextArea#setDragEnabled(true)
を設定して選択文字列をドラッグ可能に設定
FileDropTargetListener
を追加したJTextArea
DropTargetAdapter#drop(...)
をオーバーライドしてドロップイベントがDataFlavor.javaFileListFlavor
をサポートしている場合はファイルをJTextArea
に読み込んでJTabbedPane
に追加、それ以外はJTextArea
からBasicTextUI.TextTransferHandler
を取得してTransferHandler#importData(...)
を実行してテキストをドロップJTextArea#setDragEnabled(true)
を設定すれば選択文字列をドラッグ可能になるが、テキストドラッグオーバー中のキャレット描画に未対応
JTextArea
にJFrame
に設定したFileTransferHandler
を設定すると、デフォルトのBasicTextUI.TextTransferHandler
が置き換えられてテキストがドロップ不可になる- これを回避するため、以下のような
TransferHandler
でラップしてファイルとテキストのドロップに対応する方法もあるが、JTextArea#setDragEnabled(true)
を設定済みのJTextArea
でも文字列を選択してドラッグアウトが不可になるTransferHandler textHandler = textArea.getTransferHandler(); TransferHandler fileHandler = new FileTransferHandler(); textArea.setTransferHandler(new TransferHandler() { @Override public boolean canImport(TransferSupport support) { return fileHandler.canImport(support) || textHandler.canImport(support); } @Override public boolean importData(TransferSupport support) { if (support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { return fileHandler.importData(support); } else { return textHandler.importData(support); } } });