Swing のデータ転送

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

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

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

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

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

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

データ転送のサポート

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

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

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

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

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

Component エクスポート (ドラッグ、カット、コピー) インポート (ドロップ、ペースト)
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 で提供できるようになります。クリップボード用のキーボードバインドは、インストールされている現在の Look & Feel 機能に依存しています。

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

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

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

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

実装の詳細

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

TransferHandlerJComponent にインストールされている場合、Look & Feel は、次の 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 で自動的にインストールされなくなったため、Look & Feel などのコードでこれらの 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, 2013, Oracle and/or its affiliates. All rights reserved.
連絡先