Swingのデータ転送

Java 2 Platform, Standard Edition, v 1.4のリリースでは、Swingにアプリケーション間でのデータ転送のサポートが加わりました。ドラッグ・アンド・ドロップ操作はデータ転送の要求であり、グラフィカル・ポインティング・デバイスを使用したジェスチャで指定します。コピーやペーストは、多くの場合、キーボードによってデータ転送が指定されます。データ転送には、次の2つの形式があります。

データ転送のサポートをSwingに追加するときに、クリップボード転送と同様にドラッグ・アンド・ドロップも、開発者がSwingコンポーネントを使用して簡単に追加できるようにすることが目標でした。ドラッグ・アンド・ドロップに対する以前のAWTサポートは非常に柔軟性がありましたが、実装するにはかなりの複雑さがありました。また、クリップボード転送に対するAWTサポートは、自然な方法でSwingに統合されていませんでした。このリリースでは、データ転送のサポートが実装されたので、開発者は容易にこれらの強力な機能を利用することができます。

各Swingコンポーネントの状態はデータ・モデルの定義とは独立しているため、データ自体の詳細部分を気にすることなく、コンポーネント間でのデータ移動のメカニズムを実装することが簡単でした。データ転送は事実上、あるモデルから別のモデルへの部分転送です。(カット、コピー、ペーストの場合は、モデルとクリップボード間でデータが転送される。)データ転送をサポートするため、次の変更が行われました。

クイック・リファレンス: DnDをサポートするコンポーネント

コンポーネント ドラッグのサポート ドロップのサポート
JColorChooser はい はい
JEditorPane はい はい
JFileChooser はい いいえ
JFormattedTextField はい はい
JLabel ここを参照 ここを参照
JList はい いいえ
JPasswordField いいえ はい
JTable はい いいえ
JTextArea はい はい
JTextField はい はい
JTextPane はい はい
JTree はい いいえ

このドキュメントには次のセクションがあります。

データ転送のサポート

データ転送の基本は、データをコンポーネントへ、またはコンポーネントから転送する処理のサポートです。コンポーネントでこの機能が利用可能な場合は、ドラッグ・アンド・ドロップの管理メカニズムが自動的に提供されます。さらに、カット、コピー、ペーストのサポートも自動的に提供されます。この実装でもっとも重要な点は、TransferHandler新規クラスの実装です。JComponentプロパティ・メソッド、setTransferHandlerおよび getTransferHandlerで、JComponentを拡張するすべてのコンポーネントに対するデータ転送メカニズムのエントリ・ポイントが提供されます。

null以外のTransferHandlerがインストールされているときに、各コンポーネントに対してサポートされる「カット」、「コピー」、「ペースト」、および「ドロップ」の範囲を次の表に示します。このサポートは、ルック・アンド・フィールコードによって有効になります。最初はドラッグのサポートが無効にされていますが、コンポーネント上でsetDragEnabled(true)を呼び出して有効にすることができます。コンポーネントにこのようなメソッドがない場合は、なんらかのジェスチャをバインドして、ドラッグを有効にできます。

デフォルトのTransferHandlerのサポート

次に挙げたコンポーネントについては、SwingがTransferHandlerのデフォルトの実装をインストールします。デフォルトのSwingサポートがあるコンポーネントでは、transferHandlerプロパティの値がnullであるか、またはUIResourceインタフェースによってマークされている場合は、TransferHandlerComponentUIによってインストールされます。ComponentUIにインストールされたデフォルトのTransferHandler実装は、開発者がデフォルトのTransferHandlerをオーバーライドできるようにして、UIResourceインタフェースによってマークされます。次の表に提供されるサポートを示します。

DnDをサポートするコンポーネント

コンポーネント エクスポート(ドラッグ、カット、コピー) インポート(ドロップ、ペースト)
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: JEditorPanecontent-typetext/plainである場合、選択したテキストは、EditorKitwriteメソッドを通じてtext/plainとして表示される。content-typeOTHERである場合は、getSelectedTextメソッドを使ってtext/plainとして、および、EditorKitwriteメソッドを使ってOTHERとしてエクスポートされる。

1.4.1: 選択したテキストでgetSelectedTextメソッドにより返されたテキストが、text/plainとしてエクスポートされる。さらに、JEditorPanecontent-typetext/plain以外の場合、選択した内容は、EditorKitwriteメソッドを使用して他のフレーバでも提示される。

1.4: text/plain型の挿入およびgetContentTypeから返された現在の型をすべて受け入れる。現在の型(text/plain含む)に一致する型が見つかると、EditorKitreadメソッドを使ってインポートされる。それ以外の場合は、コンポーネントのreplaceSelectionメソッドを通してtext/plainがインポートされる。ペースト: 選択している内容があれば、それが置換される。ドロップ: キャレットの位置にデータが挿入される。

1.4.1: text/plain型の挿入およびgetContentTypeから返された現在の型をすべて受け入れる。現在の型(text/plain除く)に一致する型が見つかると、EditorKitreadメソッドを使ってインポートされる。それ以外の場合は、コンポーネントのreplaceSelectionメソッドを通してtext/plainがインポートされる。ペースト: 選択している内容があれば、それが置換される。ドロップ: キャレットの位置にデータが挿入される。

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

JTextFieldJLabelを使用してドラッグ・アンド・ドロップを実装した小さな例も含めてあります。テキスト・フィールドに値を入力し、テキストを強調表示したあとに、テキスト・フィールドの上にマウス・ボタンを置いて下に押さえ、ピクセルをドラッグすることができます。アイコンはカーソルの下に表示されます。JLabelの上のアイコンを解放して、テキストが「Drop Here」テキストに置き換わったことを確認してください。ドロップすると同時に、ソースのテキスト・フィールドからテキストが削除されます。ドラッグ・アンド・ドロップのデフォルトの動作はMOVEです。この動作をCOPYに変更するには、テキストを選択するときにCtrlキーを押します。Windowsでは、アイコン内にプラス記号が表示されます。テキストがターゲット上に貼り付けられても、ソース内のテキストはそのまま残ります。同様に、JLabelからテキスト・フィールドへドラッグすることもできます。JLabelにはコピーおよびペーストのバインドがなく、この機能をサポートするために必要なフォーカスを取得することができないことに留意してください。

JLabelDragNDrop.javaここの例を参照してください。

ドラッグのサポート

テキスト・フィールドなどのコンポーネントは、選択範囲をサポートします。この種のコンポーネントの場合、ドラッグ操作は通常、既存の選択範囲をマウスでドラッグすることで開始されます。この型のコンポーネントのコントローラがこの状態を認識することができ、ドラッグを開始します。選択範囲のないコンポーネントでは、Swingがドラッグを自動的に開始できませんが、JLabelの例にあるようにドラッグが試行されると、ドラッグのメカニズムを処理することはできます。

このレベルのドラッグ・サポートで、Swingの開発者は、実行したい転送を表現するTransferHandlerの実装、およびSwingコンポーネントでのプロパティの設定に集中することができます。これで、アプリケーション内でドラッグをサポートしようとするSwing開発者の負担が軽減されます。

現在は、ドラッグのさまざまな視覚上の表現方法(API内のIconへの参照)を調査中です。今後の進展に注意していてください。

デフォルトのドラッグのサポート

サポートのもっとも単純なレベルは、開発者がデフォルトのサポートが有効にされるのを望んでいることを示すフラグの設定です。ドラッグのデフォルトのサポートを提供するコンポーネントについては、「DnDをサポートするコンポーネント」の表の「エクスポート」欄に説明がありますが、要約すると、setDragEnabledおよびgetDragEnabledを直接実装するクラスは、JColorChooserJFileChooserJListJTableJTree、およびJTextComponentです。ドラッグのジェスチャは、選択範囲の上でマウスの左ボタンを押して、いくつかのピクセルをドラッグすることと定義されます。そのため、dragEnabledプロパティをtrueに設定すると、マウスの動作に関して微妙な効果があります。

ドラッグがコンポーネント上で有効にされると、対応するComponentUIサブクラス内のSwingコントローラがドラッグのジェスチャの検索を開始し、transferHandlerプロパティがnullであるか、UIResourceインタフェースによってマークされていると、デフォルトの実装がインストールされます。Swingによって提供された実装がUIResourceインタフェースでマークされるので、開発者は、デフォルトのTransferHandlerプロパティをカスタムの実装で置き換えて、新しいTransferHandlerを挿入することができます。ドラッグのジェスチャが認識されると、ドラッグ・メカニズムを開始するTransferHandler上でexportAsDragメソッドが呼び出されます。実際の転送はjava.awt.dndメカニズムによって処理され、開発者にとってこれ以上の労力は必要ありません。

Swingクラスのサブクラスへのドラッグのサポートの追加

Swingに提供されるドラッグのサポートは、TransferHandler.exportAsDragメソッドによって起動します。これによって、次のように簡単にドラッグのサポートを追加することができます。

  1. setTransferHandlerメソッドを呼び出して(ドラッグの対象がある場合)、TransferHandlerの実装をインストールする。
  2. ドラッグのジェスチャを認識する。
  3. exportAsDragメソッドを呼び出す。

これを行うシナリオには、次のようなものがあります。

TransferHandler.exportAsDragの操作

exportAsDragメソッドがTransferHandler上で呼び出されると、Swing提供の機能によってドラッグが処理されます。このメソッドが呼び出される場合は、有効なドラッグ・ジェスチャが認識されたとみなされます。このメソッドでは、次の手順が実行されます。

  1. DragSourceおよびDragListenerのSwing実装を使用して、データ転送オブジェクトとしてcreateTransferableから返されたTransferable実装を使用するドラッグを開始する。
  2. ドロップが終了すると、exportDoneメソッドがTransferHandler上で呼び出される。MOVEなどのいくつかの操作の場合は、ソースからデータを削除することが必要な場合もある。たとえば、テキストベースのコンポーネントでのデフォルトの動作は、標準的なドラッグにMOVEの動作が実装される(ドロップに続いて、選択したテキストはソース・コンポーネントから削除される)。テキストをドラッグ用に選択するときにCtrlキーを押し下げると、この動作をオーバーライドできる。Windowsでは、小さなプラス記号の付いたドラッグ・アイコンによって、コピー動作が視覚的に示される。

ドロップのサポート

ドロップを取り扱うプライマリ・サポートは、ペースト操作、つまりTransferHandlerimportDataメソッドでの場合と同じです。コンポーネントへのデータ挿入のセマンティックスは、通常、ツールキットのレベルに比べてアプリケーション・レベルでの意味のほうが多くなっています。アプリケーションのユーザーは、Swingツールキットにとってまったく未知のコンポーネント上ですべての種類のTransferable実装をドロップできます。デフォルトのTransferHandlerが不十分な場合は、意味の多いインポートのセマンティックスでTransferHandlerを提供するのがSwing開発者の責任です。

ただし、ドロップの操作はペーストと多少違います。

デフォルトのドロップのサポート

ドロップのサポートのアプリケーションへの追加でSwing開発者を支援するために、Swingによって、Swingコンポーネント上でTransferHandlerプロパティを使用するDropTargetの実装が提供されます。null以外の値のTransferHandlerプロパティがあるコンポーネントでは、dropTargetプロパティの値がnullであるか、またはUIResourceインタフェースの存在によってマークされていれば、ドロップ・ターゲットがComponentUIによってインストールされます。ComponentUIにインストールされたデフォルトのDropTarget実装は、開発者がデフォルトのDropTargetをオーバーライドできるようにして、UIResourceインタフェースによってマークされます。

ドロップの完全な実装をデフォルトで提供するコンポーネントは、「DnDをサポートするコンポーネント」表のインポート欄に示されています。ドロップを一部だけサポートしているコンポーネントは4つあります。JFileChooserJListJTable、およびJTreeには、潜在的な挿入ポイントを示すDropTargetがデフォルトでインストールされています。ただし、データのインポートを完全にサポートするには、開発者がカスタムのTransferHandlerを作成してインストールする必要があります。

Swingクラスのサブクラス内でのドラッグ・サポートの使用

DropTargetがうまく動作する実装では、ドロップを実行するためにJComponenttransferHandlerプロパティが使用されています。transferHandlerプロパティが設定され、dropTargetプロパティがnullの場合に、Swingの開発者は、ドロップをTransferHandlerにリンクさせる単純なDropTarget実装を自動的に取得します。

クリップボード転送のサポート

カット、コピー、およびペースト操作は、通常はキーボードから起動されるため、マウスを使用せずにより有用なデータ転送を実行します。これらの操作は、ドラッグ・アンド・ドロップのサポートと同じTransferHandlerサービスを使用できます。これによってデータ転送の使い易さが向上し、Swingで実際のクリップボード間とのデータ転送ができない場合であっても、このような操作のためのキーボード・バインドをSwingで提供できるようになります。クリップボード用のキーボード・バインドは、インストールされている現在のルック・アンド・フィール機能に依存しています。

デフォルトのクリップボード転送

ドラッグ・アンド・ドロップと同様に、クリップボードによる転送は、選択範囲をサポートするコンポーネントにとってもっとも役に立ちます。「DnDをサポートするコンポーネント」表のエクスポート欄に示したコンポーネントのリストには、コンポーネントの入力マップ内のキーボード・バインドに関するLAFに依存するセットに加えて、コンポーネントのアクション・マップ内にカットコピー、およびペーストのアクションがあります。Swingでこれらのバインドが提供されるので、開発者は、現在のルック・アンド・フィールの追跡とバインドの変更をしないで済みます。

Swingクラスのサブクラス内でのクリップボード転送サポートの使用

カット、コピー、およびペーストがうまく動作する実装では、転送を実行するためにJComponenttransferHandlerプロパティが使用されています。transferHandlerプロパティがJComponent上に設定されていると、現在インストールされているアクションが何もなければ、ClipboardTransferHandler間の転送にリンクする単純なAction実装が、コンポーネントのアクション・マップ内のcutcopy、およびpasteキーの下にインストールされます。

実装の詳細

: 次の説明は、非公開の実装の詳細についてと、変更の主題についてです。この情報は、ソース・コードにアクセスして、特に興味をお持ちの方々に対してだけ提供します。

TransferHandlerJComponentにインストールされている場合、ルック・アンド・フィールは、次のTransferHandlerメソッドを使ったカットコピー、およびペースト処理を有効にします。

イベントをTransferHandler.exportAsDragにバインドした場合は、ドラッグ・サポートも入手できます。この処理は、TransferHandlerクラス内部のパッケージ専用のネストされたクラス内にあります。

次のパッケージ専用のクラスが、デフォルトのサポートを作成するためにjavax.swing.plaf.basicパッケージに追加されました。

BasicTransferable
さまざまなTransferable実装の基本。
BasicDropTargetListener
選択範囲をサポートするコンポーネント用にスクロールのサポートとドロップ・ターゲットのフィードバックを追加。
BasicDragGestureRecognizer
「数ピクセルの選択と移動」のドラッグ・ジェスチャの認識のサポート。

DnDをサポートする各ComponentUIクラスには、追加のネストされたクラスがあります。

BasicTreeUI:

TreeTransferHandler
デフォルトのインポート/エクスポートのサポート。
TreeTransferable
実際のツリー構造のデータ。
TreeDragGestureRecognizer
JTree.setDragEnabledによって有効にされる、ツリー・ドラッグ・ジェスチャの認識。
TreeDropHandler
ドラッグ・ターゲットの位置の表示。

BasicListUIBasicTableUI、およびBasicTextUIはすべて、BasicTreeUIと似たパターンを持っています。

BasicFileChooserUI
リスト・サポートを使用するが、FileTransferHandlerがあり、ファイル転送で使用されるフレーバでListTransferableを拡張するFileTransferableを作成する。
BasicColorChooserUI
TransferHandlerのBeanサポートを使用し、カラーに関するプロパティをバインドする。マウス・リスナーが、マウスで押したものをTransferHandler上のexportAsDragメソッドにバインドするプレビュー領域に追加される。

Beta以降の変更点

TransferHandlerのアクションはUIで登録することになった

この変更に関連するバグ追跡レポート: 4460011

ドラッグ・アンド・ドロップを実装するために、Actionクラスでバインディングを提供して、データのコピーとペーストをサポートしていました。ActionTransferHandlerで自動的にインストールされなくなったため、ルック・アンド・フィールなどのコードでこれらのActionをオーバーライドするには、UIを通してこれらのアクションをインストールする必要があります。TransferHandler getCutAction getCopyAction、およびgetPasteActionの各メソッドは、package-privateからpublicに変更されました。

DropTargetを無効にする機能

この変更に関連するバグ追跡レポート: 4485914

ドラッグ・アンド・ドロップを実装すると、JComponentTransferHandlerがインストールされている場合、JComponentにDropTargetが追加されます。手動でDropTargetを追加しているアプリケーションは、これによって影響を受ける可能性があります。そのため、suppressSwingDropSupportというシステム・プロパティが追加されました。JComponentsetTransferHandler(TransferHandler)メソッドと getTransferHandlerメソッドを使って、このプロパティを有効にしたり無効にしたりできます。

既知のバグ

JTextComponentで選択したテキストをドロップするとテキストが壊れる

この問題に対応するバグ追跡レポート: 4513715

テキストを選択し、同じテキスト・コンポーネントの選択領域の中にドラッグ・アンド・ドロップすると、選択したテキストが壊れ、何もペーストされません。リリース1.4.1ではこのバグは修正されました。

コンポーネントから出るときキャレットの復元エラーが発生する

この問題に対応するバグ追跡レポート: 4513720

組込みのドロップ・サポートにより、Swingテキスト・コンポーネントは、ドラッグ・アンド・ドロップのドラッグオーバーに反応して、Caretを可視に設定し、そのキャレットを使って潜在的な挿入ポイントを示します。ドラッグがコンポーネントの外に出ると、Caretの可視性は元の状態に復元されます。ところが、Caretで使用するvisibleプロパティは、これ1つで通常の「可視」という意味と点滅状態との両方を表すため、Caretの可視性は正しく復元されないことがあります。

RTFEditorKitの設定されたJEditorPaneに対するカット、コピー、ドラッグが無効になった

この問題に対応するバグ追跡レポート: 4513638

setEditorKitを使用たりcontent-typetext/rtfを設定したりしてJEditorPaneに明示的に設定されたRTFEditorKitを使用するときに、カット、コピー、およびドラッグは動作しなくなりました。このバグはリリース1.4で報告されましたが、1.4.1では修正されました。


Copyright © 1993, 2020, Oracle and/or its affiliates. All rights reserved.