Java 2 Platform, Standard Edition, v 1.4のリリースでは、Swingにアプリケーション間でのデータ転送のサポートが加わりました。 ドラッグ・アンド・ドロップ操作はデータ転送の要求であり、グラフィカル・ポインティング・デバイスを使用したジェスチャで指定します。 コピーやペーストは、多くの場合、キーボードによってデータ転送が指定されます。 データ転送には、次の2つの形式があります。
各Swingコンポーネントの状態はデータ・モデルの定義とは独立しているため、データ自体の詳細部分を気にすることなく、コンポーネント間でのデータ移動のメカニズムを実装することが簡単でした。 データ転送は事実上、あるモデルから別のモデルへの部分転送です。 (カット、コピー、ペーストの場合は、モデルとクリップボード間でデータが転送される。) データ転送をサポートするため、次の変更が行われました。
| コンポーネント | ドラッグのサポート | ドロップのサポート |
|---|---|---|
JColorChooser |
はい | はい |
JEditorPane |
はい | はい |
JFileChooser |
はい | いいえ |
JFormattedTextField |
はい | はい |
JLabel |
ここを参照 | ここを参照 |
JList |
はい | いいえ |
JPasswordField |
いいえ | はい |
JTable |
はい | いいえ |
JTextArea |
はい | はい |
JTextField |
はい | はい |
JTextPane |
はい | はい |
JTree |
はい | いいえ |
このドキュメントには次のセクションがあります。
データ転送の基本は、データをコンポーネントへ、またはコンポーネントから転送する処理のサポートです。 コンポーネントでこの機能が利用可能な場合は、ドラッグ・アンド・ドロップの管理メカニズムが自動的に提供されます。 さらに、カット、コピー、ペーストのサポートも自動的に提供されます。 この実装でもっとも重要な点は、TransferHandler新規クラスの実装です。 JComponentプロパティ・メソッド、setTransferHandlerおよび getTransferHandlerで、JComponentを拡張するすべてのコンポーネントに対するデータ転送メカニズムのエントリ・ポイントが提供されます。
null以外のTransferHandlerがインストールされているときに、各コンポーネントに対してサポートされる「カット」、「コピー」、「ペースト」、および「ドロップ」の範囲を次の表に示します。 このサポートは、ルック・アンド・フィールコードによって有効になります。 最初はドラッグのサポートが無効にされていますが、コンポーネント上でsetDragEnabled(true)を呼び出して有効にすることができます。 コンポーネントにこのようなメソッドがない場合は、なんらかのジェスチャをバインドして、ドラッグを有効にできます。
TransferHandlerのデフォルトの実装をインストールします。 デフォルトのSwingサポートがあるコンポーネントでは、transferHandlerプロパティの値がnullであるか、またはUIResourceインタフェースによってマークされている場合は、TransferHandlerがComponentUIによってインストールされます。 ComponentUIにインストールされたデフォルトのTransferHandler実装は、開発者がデフォルトのTransferHandlerをオーバーライドできるようにして、UIResourceインタフェースによってマークされます。 次の表に提供されるサポートを示します。
| コンポーネント | エクスポート(ドラッグ、カット、コピー) | インポート(ドロップ、ペースト) |
|---|---|---|
JColorChooser |
選択したカラーが、TransferHandlerのJavaBeansプロパティ処理を通じて提示される。 提示されたフレーバは、application/x-java-jvm-local-objectref; class=java.awt.Colorである。 転送される値はgetColorによって決定される。 |
Color型の挿入を受け入れる。 データは、Beanのプロパティ処理からsetColorを使用してインポートされる。 class=java.awt.Colorまたはjava.awt.Colorのサブクラスを持つすべてのフレーバが受け入れられる。 |
JEditorPane |
1.4: JEditorPaneのcontent-typeがtext/plainである場合、選択したテキストは、EditorKitのwriteメソッドを通じてtext/plainとして表示される。 content-typeがOTHERである場合は、getSelectedTextメソッドを使ってtext/plainとして、および、EditorKitのwriteメソッドを使ってOTHERとしてエクスポートされる。
1.4.1: 選択したテキストで |
1.4: text/plain型の挿入およびgetContentTypeから返された現在の型をすべて受け入れる。 現在の型(text/plainも含む)に一致する型が見つかると、EditorKitのreadメソッドを使ってインポートされる。 それ以外の場合は、コンポーネントのreplaceSelectionメソッドを通してtext/plainがインポートされる。 ペースト: 選択している内容があれば、それが置換される。 ドロップ: キャレットの位置にデータが挿入される。
1.4.1: |
JFileChooser |
ネイティブのファイル・チューザと同じ方法で選択範囲が提示される。 | インポートは受け入れられない。 マウスがリスト上に移動すると、カーソルの下のファイルやディレクトリが強調表示されて、潜在的なドロップ・ポイントが示される。 デフォルトのドロップのサポートを参照。 |
JFormattedTextField |
選択したテキストがtext/plainとして提示される。 |
text/plain型の挿入を受け入れる。 ペースト: 選択している内容があれば、それが置換される。何も選択していない場合は、キャレットの位置にデータが挿入される。 ドロップ: キャレットの位置にデータが挿入される。 ペーストとドロップは、キーボードからの入力時と同じコード・パスを採用するので、コードの検証が保存される。 |
JList |
1項目が選択された場合は、text/plainとして提示される。 複数の項目が選択された場合は、text/htmlとして提示される。 text/htmlの形式は、<UL>タグのあとに、それぞれが<LI>タグで始まる選択したリスト項目が続く。 |
インポートは受け入れられない。 マウスがリスト上に移動すると、カーソルの下のリスト項目が強調表示されて、潜在的なドロップ・ポイントが示される。 デフォルトのドロップのサポートを参照。 |
JPasswordField |
セキュリティ上の理由から、カット、コピー、およびドラッグはサポートされない。 | text/plain型の挿入を受け入れる。 ペースト: 選択している内容があれば、それが置換される。何も選択していない場合は、キャレットの位置にデータが挿入される。 ドロップ: キャレットの位置にデータが挿入される。 |
JTable |
1項目が選択された場合は、text/plainとして提示される。 複数の項目が選択された場合は、text/htmlとして提示される。 text/htmlの形式は、<TABLE>タグのあとに各行には<TR>タグ、各セルには<TD>タグが続く。 |
インポートは受け入れられない。 マウスが表の上に移動すると、カーソルの下のセルが強調表示されて、潜在的なドロップ・ポイントが示される。 デフォルトのドロップのサポートを参照。 |
JTextArea |
選択したテキストがtext/plainとして提示される。 |
text/plain型の挿入を受け入れる。 ペースト: 選択している内容があれば、それが置換される。何も選択していない場合は、キャレットの位置にデータが挿入される。 ドロップ: キャレットの位置にデータが挿入される。 |
JTextField |
選択したテキストがtext/plainとして提示される。 |
text/plain型の挿入を受け入れる。 ペースト: 選択している内容があれば、それが置換される。何も選択していない場合は、キャレットの位置にデータが挿入される。 ドロップ: キャレットの位置にデータが挿入される。 |
JTextPane |
JEditorPaneと同じ。 |
JEditorPaneと同じ。 |
JTree |
1項目が選択された場合は、text/plainとして提示される。 複数の項目が選択された場合は、text/htmlとして提示される。 text/htmlの形式は、JListに使用される形式と似た、ネストされたリストである。 |
インポートは受け入れられない。 マウスが表の上に移動すると、カーソルの下のツリー・ノードが強調表示されて、潜在的なドロップ・ポイントが示される。 デフォルトのドロップのサポートを参照。 |
JLabelへのサポート追加の例特に指定しないかぎり、JLabelコンポーネントでDnDはサポートされません。 次のコーディングにより、「テキスト」のプロパティ(String)でドラッグ・アンド・ドロップをサポートするJLabelが作成されます。
JLabel componentType = new JLabel();
componentType.setTransferHandler(new TransferHandler("text"));
MouseListener ml = new MouseAdapter() {
public void mousePressed(MouseEvent e) {
JComponent c = (JComponent)e.getSource();
TransferHandler th = c.getTransferHandler();
th.exportAsDrag(c, e, TransferHandler.COPY);
}
};
componentType.addMouseListener(ml);
JTextFieldとJLabelを使用してドラッグ・アンド・ドロップを実装した小さな例も含めてあります。 テキスト・フィールドに値を入力し、テキストを強調表示したあとに、テキスト・フィールドの上にマウス・ボタンを置いて下に押さえ、ピクセルをドラッグすることができます。 アイコンはカーソルの下に表示されます。 JLabelの上のアイコンを解放して、テキストが「Drop Here」テキストに置き換わったことを確認してください。 ドロップすると同時に、ソースのテキスト・フィールドからテキストが削除されます。 ドラッグ・アンド・ドロップのデフォルトの動作はMOVEです。 この動作をCOPYに変更するには、テキストを選択するときにCtrlキーを押します。 Windowsでは、アイコン内にプラス記号が表示されます。 テキストがターゲット上に貼り付けられても、ソース内のテキストはそのまま残ります。 同様に、JLabelからテキスト・フィールドへドラッグすることもできます。 JLabelにはコピーおよびペーストのバインドがなく、この機能をサポートするために必要なフォーカスを取得することができないことに留意してください。
JLabelDragNDrop.javaのここの例を参照してください。
テキスト・フィールドなどのコンポーネントは、選択範囲をサポートします。 この種のコンポーネントの場合、ドラッグ操作は通常、既存の選択範囲をマウスでドラッグすることで開始されます。 この型のコンポーネントのコントローラがこの状態を認識することができ、ドラッグを開始します。 選択範囲のないコンポーネントでは、Swingがドラッグを自動的に開始できませんが、JLabelの例にあるようにドラッグが試行されると、ドラッグのメカニズムを処理することはできます。
このレベルのドラッグ・サポートで、Swingの開発者は、実行したい転送を表現するTransferHandlerの実装、およびSwingコンポーネントでのプロパティの設定に集中することができます。 これで、アプリケーション内でドラッグをサポートしようとするSwing開発者の負担が軽減されます。
現在は、ドラッグのさまざまな視覚上の表現方法(API内のIconへの参照)を調査中です。 今後の進展に注意していてください。
サポートのもっとも単純なレベルは、開発者がデフォルトのサポートが有効にされるのを望んでいることを示すフラグの設定です。 ドラッグのデフォルトのサポートを提供するコンポーネントについては、「DnDをサポートするコンポーネント」の表の「エクスポート」欄に説明がありますが、要約すると、setDragEnabledおよびgetDragEnabledを直接実装するクラスは、JColorChooser、JFileChooser、JList、JTable、JTree、およびJTextComponentです。 ドラッグのジェスチャは、選択範囲の上でマウスの左ボタンを押して、いくつかのピクセルをドラッグすることと定義されます。 そのため、dragEnabledプロパティをtrueに設定すると、マウスの動作に関して微妙な効果があります。
ドラッグがコンポーネント上で有効にされると、対応するComponentUIサブクラス内のSwingコントローラがドラッグのジェスチャの検索を開始し、transferHandlerプロパティがnullであるか、UIResourceインタフェースによってマークされていると、デフォルトの実装がインストールされます。 Swingによって提供された実装がUIResourceインタフェースでマークされるので、開発者は、デフォルトのTransferHandlerプロパティをカスタムの実装で置き換えて、新しいTransferHandlerを挿入することができます。 ドラッグのジェスチャが認識されると、ドラッグ・メカニズムを開始するTransferHandler上でexportAsDragメソッドが呼び出されます。 実際の転送はjava.awt.dndメカニズムによって処理され、開発者にとってこれ以上の労力は必要ありません。
Swingに提供されるドラッグのサポートは、TransferHandler.exportAsDragメソッドによって起動します。 これによって、次のように簡単にドラッグのサポートを追加することができます。
setTransferHandlerメソッドを呼び出して(ドラッグの対象がある場合)、TransferHandlerの実装をインストールする。exportAsDragメソッドを呼び出す。これを行うシナリオには、次のようなものがあります。
MouseListenerを追加して、次にコンポーネント上でgetTransferHandlerを呼び出し、ドラッグのジェスチャが検出されるとexportAsDragを呼び出す。 JLabelの例を参照。 processMouseEventメソッドを再実装し、ドラッグのジェスチャが検出されたときにComponentUI変数上でexportAsDragメソッドを呼び出す。そうでないときは、スーパー・クラスの動作を実行する。exportAsDragを呼び出すようにする。exportAsDragメソッドがTransferHandler上で呼び出されると、Swing提供の機能によってドラッグが処理されます。 このメソッドが呼び出される場合は、有効なドラッグ・ジェスチャが認識されたとみなされます。 このメソッドでは、次のステップが実行されます。
DragSourceおよびDragListenerのSwing実装を使用して、データ転送オブジェクトとしてcreateTransferableから返されたTransferable実装を使用するドラッグを開始する。exportDoneメソッドがTransferHandler上で呼び出される。 MOVEなどのいくつかの操作の場合は、ソースからデータを削除することが必要な場合もある。 たとえば、テキストベースのコンポーネントでのデフォルトの動作は、標準的なドラッグにMOVEの動作が実装される(ドロップに続いて、選択したテキストはソース・コンポーネントから削除される)。 テキストをドラッグ用に選択するときにCtrlキーを押し下げると、この動作をオーバーライドできる。 Windowsでは、小さなプラス記号の付いたドラッグ・アイコンによって、コピー動作が視覚的に示される。 ドロップを取り扱うプライマリ・サポートは、ペースト操作、つまりTransferHandlerのimportDataメソッドでの場合と同じです。 コンポーネントへのデータ挿入のセマンティックスは、通常、ツールキットのレベルに比べてアプリケーション・レベルでの意味のほうが多くなっています。 アプリケーションのユーザーは、Swingツールキットにとってまったく未知のコンポーネント上ですべての種類のTransferable実装をドロップできます。 デフォルトのTransferHandlerが不十分な場合は、意味の多いインポートのセマンティックスでTransferHandlerを提供するのがSwing開発者の責任です。
ただし、ドロップの操作はペーストと多少違います。
ドロップのサポートのアプリケーションへの追加でSwing開発者を支援するために、Swingによって、Swingコンポーネント上でTransferHandlerプロパティを使用するDropTargetの実装が提供されます。 null以外の値のTransferHandlerプロパティがあるコンポーネントでは、dropTargetプロパティの値がnullであるか、またはUIResourceインタフェースの存在によってマークされていれば、ドロップ・ターゲットがComponentUIによってインストールされます。 ComponentUIにインストールされたデフォルトのDropTarget実装は、開発者がデフォルトのDropTargetをオーバーライドできるようにして、UIResourceインタフェースによってマークされます。
ドロップの完全な実装をデフォルトで提供するコンポーネントは、「DnDをサポートするコンポーネント」表のインポート欄に示されています。 ドロップを一部だけサポートしているコンポーネントは4つあります。 JFileChooser、JList、JTable、およびJTreeには、潜在的な挿入ポイントを示すDropTargetがデフォルトでインストールされています。 ただし、データのインポートを完全にサポートするには、開発者がカスタムのTransferHandlerを作成してインストールする必要があります。
DropTargetがうまく動作する実装では、ドロップを実行するためにJComponentでtransferHandlerプロパティが使用されています。 transferHandlerプロパティが設定され、dropTargetプロパティがnullの場合に、Swingの開発者は、ドロップをTransferHandlerにリンクさせる単純なDropTarget実装を自動的に取得します。
カット、コピー、およびペースト操作は、通常はキーボードから起動されるため、マウスを使用せずにより有用なデータ転送を実行します。 これらの操作は、ドラッグ・アンド・ドロップのサポートと同じTransferHandlerサービスを使用できます。 これによってデータ転送の使い易さが向上し、Swingで実際のクリップボード間とのデータ転送ができない場合であっても、このような操作のためのキーボード・バインドをSwingで提供できるようになります。 クリップボード用のキーボード・バインドは、インストールされている現在のルック・アンド・フィール機能に依存しています。
ドラッグ・アンド・ドロップと同様に、クリップボードによる転送は、選択範囲をサポートするコンポーネントにとってもっとも役に立ちます。 DnDをサポートするコンポーネント表のエクスポート欄に示したコンポーネントのリストには、コンポーネントの入力マップ内のキーボード・バインドに関するLAFに依存するセットに加えて、コンポーネントのアクション・マップ内にカット、コピー、およびペーストのアクションがあります。 Swingでこれらのバインドが提供されるので、開発者は、現在のルック・アンド・フィールの追跡とバインドの変更をしないで済みます。
カット、コピー、およびペーストがうまく動作する実装では、転送を実行するためにJComponentでtransferHandlerプロパティが使用されています。 transferHandlerプロパティがJComponent上に設定されていると、現在インストールされているアクションが何もなければ、ClipboardとTransferHandler間の転送にリンクする単純なAction実装が、コンポーネントのアクション・マップ内のcut、copy、およびpasteキーの下にインストールされます。
ノート: 次の説明は、非公開の実装の詳細についてと、変更の主題についてです。 この情報は、ソース・コードにアクセスして、特に興味をお持ちの方々に対してだけ提供します。
TransferHandlerがJComponentにインストールされている場合、ルック・アンド・フィールは、次のTransferHandlerメソッドを使ったカット、コピー、およびペースト処理を有効にします。
TransferHandler.exportAsDragにバインドした場合は、ドラッグ・サポートも入手できます。 この処理は、TransferHandlerクラス内部のパッケージ専用のネストされたクラス内にあります。
次のパッケージ専用のクラスが、デフォルトのサポートを作成するためにjavax.swing.plaf.basicパッケージに追加されました。
BasicTransferableTransferable実装の基本。BasicDropTargetListenerBasicDragGestureRecognizerDnDをサポートする各ComponentUIクラスには、追加のネストされたクラスがあります。
BasicTreeUI:
TreeTransferHandlerTreeTransferableTreeDragGestureRecognizerJTree.setDragEnabledによって有効にされる、ツリー・ドラッグ・ジェスチャの認識。TreeDropHandlerBasicListUI、BasicTableUI、およびBasicTextUIはすべて、BasicTreeUIと似たパターンを持っています。
BasicFileChooserUIFileTransferHandlerがあり、ファイル転送で使用されるフレーバでListTransferableを拡張するFileTransferableを作成する。BasicColorChooserUITransferHandlerのBeanサポートを使用し、カラーに関するプロパティをバインドする。 マウス・リスナーが、マウスで押したものをTransferHandler上のexportAsDragメソッドにバインドするプレビュー領域に追加される。 この変更に関連するバグ追跡レポート: 4460011。
ドラッグ・アンド・ドロップを実装するために、Actionクラスでバインディングを提供して、データのコピーとペーストをサポートしていました。 ActionがTransferHandlerで自動的にインストールされなくなったため、ルック・アンド・フィールなどのコードでこれらのActionをオーバーライドするには、UIを通してこれらのアクションをインストールする必要があります。 TransferHandlerの getCutAction、 getCopyAction、およびgetPasteActionの各メソッドは、package-privateからpublicに変更されました。
この変更に関連するバグ追跡レポート: 4485914。
ドラッグ・アンド・ドロップを実装すると、JComponentにTransferHandlerがインストールされている場合、JComponentにDropTargetが追加されます。 手動でDropTargetを追加しているアプリケーションは、これによって影響を受ける可能性があります。 そのため、suppressSwingDropSupportというシステム・プロパティが追加されました。 JComponentのsetTransferHandler(TransferHandler)メソッドと getTransferHandlerメソッドを使って、このプロパティを有効にしたり無効にしたりできます。
この問題に対応するバグ追跡レポート: 4513715。
テキストを選択し、同じテキスト・コンポーネントの選択領域の中にドラッグ・アンド・ドロップすると、選択したテキストが壊れ、何もペーストされません。 リリース1.4.1ではこのバグは修正されました。
この問題に対応するバグ追跡レポート: 4513720。
組込みのドロップ・サポートにより、Swingテキスト・コンポーネントは、ドラッグ・アンド・ドロップのドラッグオーバーに反応して、Caretを可視に設定し、そのキャレットを使って潜在的な挿入ポイントを示します。 ドラッグがコンポーネントの外に出ると、Caretの可視性は元の状態に復元されます。 ところが、Caretで使用するvisibleプロパティは、これ1つで通常の「可視」という意味と点滅状態との両方を表すため、Caretの可視性は正しく復元されないことがあります。
この問題に対応するバグ追跡レポート: 4513638。
setEditorKitを使用たりcontent-typeにtext/rtfを設定したりしてJEditorPaneに明示的に設定されたRTFEditorKitを使用するときに、カット、コピー、およびドラッグは動作しなくなりました。 このバグはリリース1.4で報告されましたが、1.4.1では修正されました。