このドキュメントには次のセクションがあります。
この仕様では、Java 2 プラットフォームのドラッグ&ドロップ機能の API を定義します。
この仕様で規定するプライマリ要件は、次のとおりです。
java.awt.datatransfer.*
パッケージを活用して、MIME 標準ベースの拡張可能なデータ型システムに記述されている、データの転送を使用可能にする。この仕様は、上で言及した以前の研究から派生していますが、JavaBeans イベントモデルや軽量 (Swing) コンポーネントが出現し、クロスプラットフォームの統合と相互運用性の問題の理解が深まってきた結果、元の研究とはかなり異なった仕様が組み入れられています。
以降のセクションでは、ドラッグ&ドロップ API について説明します。
ドラッグ&ドロップは、多くのグラフィカルユーザーインタフェース (GUI) システムにみられる直接的な操作のジェスチャーで、GUI 内の表現要素に論理的に関連付けられた 2 つの構成要素間で情報を転送するためのメカニズムを提供します。通常、ドラッグ&ドロップは、ユーザーが適切な入力デバイスを使用して行う物理的なジェスチャーによって生じます。ドラッグ&ドロップは、GUI の表現要素上でデータ転送の結果がわかるように、ナビゲーション中に、ユーザーに継続的にフィードバックするメカニズムと、続いて行われるデータのネゴシエーションおよび転送を容易にする機能を提供します。
一般的なドラッグ&ドロップ操作は、次のようにいくつかの状態に分けることができます (この順番どおり行われるわけではない)。
Transferable
(転送可能になり得る) データのドラッグ&ドロップを開始するために、GUI の表現要素 (Component
) に関連付けられた DragSource
(ドラッグソース) が作成されます。Transferable
データ型を消費できる可能性のある、GUI の表現要素 (Components
) に関連付けられた 1 つ以上の DropTarget
が生成または削除されます。DragGestureRecognizer
が DragSource
から取得され、ユーザーのドラッグ開始ジェスチャーを Component
上で追跡し識別するために、Component
と関連付けられます。Component
上でドラッグジェスチャーを行うと、登録された DragGestureRecognizer
がそれを検出し、その DragGestureListener
に通知します。
注:このドキュメントでは、ドラッグ&ドロップ操作の開始要因が、人間であるユーザーによる物理的なジェスチャーであることを繰り返し言及していますが、これには、DragSource
が適切に実装されている場合の、プログラムによるドラッグ&ドロップ操作も含まれています。
DragGestureListener
によって、DragSource
がユーザーの代わりにドラッグ&ドロップ操作を開始します。このとき、GUI Cursor
がアニメーション化されたり、操作の対象である項目の Image
がレンダリングされたりすることがあります。DropTarget
が関連付けられている GUI の Component
の上を移動すると、サポートされる操作および関連するデータ型に基づいて、DragSource
は「ドラッグオーバー」フィードバック効果を提供するために通知を受信し、DropTarget
は「ドラッグアンダー」フィードバック効果を提供するために通知を受け取ります。
ジェスチャー自体は、論理カーソルを GUI 階層全体にわたって移動し、GUI Component
の幾何学的図形と交差します。これにより、論理的な Drag カーソルが Component
とそれに関連付けられた DropTarget
に入り、横切り、その後離れる可能性があります。
DragSource
オブジェクトはユーザーに「ドラッグオーバー」フィードバックを示します。通常の場合、論理カーソルに関連した GUI Cursor
を動画化します。
DropTarget
オブジェクトは、通常は関連付けられた GUI Component
の GUI Cursor
にアニメーションをレンダリングすることによって、「ドラッグアンダー」フィードバックをユーザーに示します。
DragSource
と DropTarget
の両方がサポートする変換「操作」、つまり Copy、Move または Reference(link) によって、パラメータ化される。DragSource
が提供するデータ型のセットと、DropTarget
が包括できるデータ型のセットとの共通部分によって、パラメータ化される。DragSource
および DropTarget
は、DragSource
に関連した情報を含みその情報の型のネゴシエーションおよび変換となる通知を、Transferable
オブジェクトを介して受け取る。このドキュメントの以降の部分では、このモデルをサポートするために提案された API の変更の詳細について説明します。
ドラッグ&ドロップ操作を開始できるジェスチャーは、プラットフォーム、Component
、およびデバイスごとに異なります。このため、操作の依存性をカプセル化するためのメカニズムが必要です。このメカニズムがあれば、ドラッグ&ドロップ操作を開始する Component
の作成が簡単になります。
DragGestureRecognizer
は、すべてのデバイス、プラットフォーム、および Component
固有のドラッグ&ドロップジェスチャーレコグナイザ用の抽象基底クラスで、次のように定義されています。
public abstract DragGestureRecognizer { protected DragGestureRecognizer( DragSource ds, Component c, int srcActions, DragGestureListener dgl ); public Component getComponent(); public void setComponent(Component c); public int getSourceActions(); public void setSourceActions(int actions); public java.awt.InputEvent getTriggerEvent(); public void resetRecognizer(); public void addDragGestureListener( DragGestureListener dgl ) throws TooManyListenerExceptions; public void removeDragGestureListener( DragGestureListener dgl ); protected abstract void registerListeners(); protected abstract void unregisterListeners(); protected void fireDragGestureRecognized( int dragAction ); protected void appendEvent(InputEvent awtie); }
DragGestureRecognizer
に適した特定の具象サブクラスは、DragSource
インスタンス、Toolkit
など、さまざまな方法で取得できます。具象実装サブクラスは、Class
参照を抽象 DragGestureRecognizer
スーパークラスに指定することによって、標準 API から取得できます。この実パラメータの具象サブクラスは、インスタンス化されてリクエスタに返されます。
DragGestureRecognizer
インスタンスが Component
および DragSource
に関連付けられると、そのインスタンスの特定の EventListener
セットがターゲット Component
とともに登録されて、その Component
に提供されたイベントのいくつかが監視され、開始ジェスチャーが検出されます。registerListeners
および unregisterListeners
を使用して、これらの監視 EventListener
の追加および削除を行うことができます。
指定された Component
または DragSource
が、その DragGestureRecognizer
に対して正しい状態にないか、その DragGestureRecognizer と相互運用性がない場合は、DragGestureRecognizer
によって、IllegalStateException
または IllegalArgumentException
がスローされる可能性があります。
DragGestureRecognizer
の具象インスタンスによって、関連する Component
上でドラッグを開始するユーザージェスチャーが検出されたときは、DragGestureListener
イベントのユニキャストイベントソース上に登録されている DragGestureListener
に対して DragGestureEvent
が発生します。この DragGestureListener
は、関連付けられた DragSource
に (必要に応じて) ドラッグ&ドロップ操作の開始を促します。
実装は、マウスデバイスジェスチャーを認識するために (少なくとも) 抽象サブクラス MouseDragGestureRecognizer
を提供します。ほかの入力デバイスまたは特定の Component クラスのセマンティクスをサポートするために、プラットフォームによってほかの抽象サブクラスが提供されることがあります。この MouseDragGestureRecognizer
の具象スーパークラスでは、プラットフォームに依存するマウスベースのジェスチャーがカプセル化されます。この具象スーパークラスは、createDragGestureRecognizer(Class adgrc, DragSource ds, Component c, int sa, DragGestureListener dgl)
メソッドを介して Toolkit
オブジェクトから取得できます。この Toolkit
の API から、プラットフォームに依存する具象実装が提供されます。この実装は、プラットフォームに依存しない特定の抽象定義 (クラス) が継承されています。
MouseDragGestureRecognizer
抽象クラスは、次のように定義されています。
public abstract MouseDragGestureRecognizer extends DragGestureRecognizer implements MouseListener, MouseMotionListener { public MouseDragGestureRecognizer( DragSource ds, Component c, int sa, DragGestureListener dsl ); //... }
DragGestureListener
は、次のように定義されます。
public interface DragGestureListener extends EventListener { void dragGestureRecognized(DragGestureEvent dge); }
通常、dragGestureRecognized()
メソッドは単に、DragGestureEvent
の簡易 API startDrag
を使って、関連する DragSource
上でドラッグ&ドロップ操作を開始します。
開始ジェスチャーに影響する各 Component
(クラスまたはインスタンス) の動作は、通常、この DragGestureListener
メソッドに実装されるか、適切または可能な場合は DragGestureRecognizer
サブクラスに実装されます。
DragGestureEvent
は、次のように定義されます。
publc class DragGestureEvent extends EventObject { public DragGestureEvent(DragGestureRecognizer dgr, int dragAction, java.util.List events ); public DragGestureRecognizer getSourceAsDragGestureRecognizer(); public Component getComponent(); public DragSource getDragSource(); public java.util.Iterator iterator(); public Object[] toArray(); public Object[] toArray(Object[] array); public int getDragAction(); public startDrag(Cursor dragCursor, Transferable t, DragSourceListener dsl ); public startDrag(Cursor dragCursor, Image dragImage, Point imageOffset, Transferable t, DragSourceListener dsl ); //... }
DragGestureEvent
によって、直前に認識されたジェスチャーの特性に関する情報がすべてカプセル化されます。次の情報がカプセル化されます。
DragGestureRecognizer
Component
DragSource
InputEvent
オブジェクトのリスト。DragSource
(ドラッグ元) は、ドラッグ&ドロップ操作を開始する構成要素です。
DragSource
および関連付けられた定数のインタフェースは、次のように定義されています。
DnDConstants
クラスは、転送対象に適用される可能性のある操作を定義しています。
public final class java.awt.dnd.DnDConstants { public static int ACTION_NONE = 0x0; public static int ACTION_COPY = 0x1; public static int ACTION_MOVE = 0x2; public static int ACTION_COPY_OR_MOVE= ACTION_COPY | ACTION_MOVE; public static int ACTION_REFERENCE = 0x40000000; } public class java.awt.dnd.DragSource { public static Cursor DefaultCopyDrop; public static Cursor DefaultMoveDrop; public static Cursor DefaultLinkDrop; public static Cursor DefaultCopyNoDrop; public static Cursor DefaultMoveNoDrop; public static Cursor DefaultLinkNoDrop; public static DragSource getDefaultDragSource(); public static boolean isDragImageSupported(); public void startDrag(DragGestureEvent trigger, Cursor dragCursor, Image dragImage, Point dragImageOffset, Transferable transferable, DragSourceListener dsl, FlavorMap fm) throws InvalidDnDOperationException; protected DragSourceContext createDragSourceContext( DragSourceContextPeer dscp, DragGestureEvent trigger, Cursor dragCursor, Image dragImage, Point dragImageOffset, Transferable transferable, DragSourceListener dsl ); public FlavorMap getFlavorMap(); public DragGestureRecongizer createDragGestureRecognizer( Class abstractRecognizerClass, Component c, int srcActions, DragGestureListener dgl ); public DragGestureRecongizer createDefaultDragGestureRecognizer( Component c, int srcActions, DragGestureListener dgl ); //... }
DragSource
は、数多くの状況で使用される可能性があります。
TextField
など) のクラスごとに 1 インスタンス。実装により異なるComponent
のインスタンス、または Component
インスタンスに関連付けられているアプリケーション固有のオブジェクトごとに 1 つ。実装により異なる制御オブジェクトは、ドラッグ操作を処理するために、ユーザーのジェスチャーの前に DragSource
のインスタンスを取得して、関連する Component
を有効にします。インスタンスを取得したら、DragGestureRecognizer
を取得して、DragSource
を Component
に関連付ける必要があります。
ユーザーのジェスチャーの最初の解釈、および以降のドラッグ操作の開始は、通常は DragGestureRecognizer
によって実装される実装側の Component
の役割です。
ジェスチャーが発生すると、ユーザーによる操作ジェスチャーを処理し、ドラッグ&ドロッププロトコルの通知を配布するために、DragSource
の startDrag
メソッドが呼び出されます。DragSource
は、どの時点においても現在の操作として 1 つのドラッグ&ドロップ操作のみを許可し、それ以上の startDrag
要求はすべて、現在の操作が完了するまで IllegalDnDOperationException
をスローすることによって拒否します。
ドラッグ操作を開始するために、startDrag
メソッドの呼び出し元は、次のパラメータを提供します。
DragGestureEvent
。Cursor
(ユーザーに対して No Drop の視覚的なフィードバックを提供する Cursor
)。Image
(オプション)。この機能をサポート可能なプラットフォーム上では、ドラッグイメージを操作に関連付けて、より忠実に Drag Over をフィードバックできます。このイメージは、通常は、ドラッグされる 1 つまたは複数のオブジェクトの小さな「アイコン」の表示で、背後のシステムは、Cursor
アニメーションの動きを追跡しながらこのイメージを読み込みます。イメージは、Cursor アニメーションと同時に動きますが、通常は、Cursor アニメーションとは別のものです。
この機能が利用できない箇所、または背後のシステムがレンダリングするのに適切でない種類のイメージの場合、このパラメータは無視され、結果的に Cursor
の「Drag Over」アニメーションだけになるので、アプリケーションは、この機能に依存しません。特定のプラットフォーム上にこの機能が存在するかどうかは、static メソッド isDragImageSupported
を呼び出すことによってテストできます。
Image
が渡された場合には Point
(Component)
の座標空間内) は、ドラッグ「Cursor」の「ホットスポット」の座標に対する相対位置で Image
の起点が指定される。Component
の座標空間内において、最初のジェスチャーの時点で、その「ホットスポット」に対する相対位置に、Image
の「Drag Over」アニメーションを適切に配置して開始するためにある。DataFlavor
(データの型) を記述した、Transferable
のインスタンス。
Transferable
のインスタンスは、ドラッグ操作の開始時に DragSource
に関連付けられ、ドラッグ&ドロップのオペランドまたは対象である、オブジェクトまたはデータを表しています。これは、ドラッグ操作のあと、DropTarget
に関連付けられた Component
上でドロップが成功した結果として、DragSource
から DropTarget
に渡される情報です。
コンテナオブジェクトを作成し、転送の対象にして Transferable
を実装することによって、同じ種類または異なる種類のオブジェクトの複数コレクションをドラッグ&ドロップ操作の対象にすることも可能です。ただし、ターゲットとなるどのネイティブプラットフォームシステムでも、このようなコレクションを記述および転送するメカニズムは標準ではサポートされていません。そのため、透過的かつプラットフォーム移植性の高い方法では、このような転送を実装することはできません。
DragSourceListener
のインスタンス。前述したように、startDrag
メソッドのプライマリの役割は、ユーザーのためにドラッグを開始することです。このためには、startDrag
メソッドは、操作そのものを追跡するための DragSourceContext
のインスタンスを作成する必要があります。さらに重要なことは、このメソッドは、基本的なプラットフォーム実装内で、操作をそのものを開始しなければならないことです。これを行うために、DragSource
は、まず基本的なシステムから (通常は java.awt.Toolkit.createDragSourceContextPeer
メソッドの呼び出しにより) DragSourceContextPeer
を取得してから、新しく作成された DragSourceContextPeer
(基本的なシステムの機能に対してプラットフォームに依存しないインタフェースを提供する) を DragSourceContext
に関連付ける必要があります。startDrag
メソッドは、createDragSourceContext
メソッドを呼び出して、適切な DragSourceContext
のインスタンスを生成し、DragSourceContextPeer
を関連付けます。
ドラッグ&ドロップシステムが、何らかの理由でドラッグ操作を開始できない場合は、startDrag
メソッドは、java.awt.dnd.InvalidDnDOperationException
をスローしてその状態を示します。この例外は通常、基礎になるプラットフォームシステムがドラッグを開始する状態にないか、あるいは指定されたパラメータが無効な場合にスローされます。
ドラッグ操作中には、ソースがドラッグ操作の開始時に公開した操作のセットは、変更できないことに注意してください。つまり、ドラッグ操作中は、DragSource
に関する操作が一定である必要があります。
getFlavorMap
メソッドは、Transferable
によって公開された DataFlavors
を、基盤のドラッグ&ドロッププラットフォームのデータ型名にマップするために、基本的なシステムによる FlavorMap
オブジェクトの取得に使われます。(FlavorMap
の詳細は、以降を参照)
「private」 FlavorMap
は、DragSource
の startDrag()
メソッドに渡すことができます。null も渡すことができますが、この場合は、DragSource
クラスまたはインスタンスの「デフォルト」の FlavorMap
が使用されます。
DragSource
の startDrag
メソッドが正常に呼び出された結果、DragSourceContext
クラスのインスタンスが作成されます。このインスタンスは、DragSource
のために操作の状態を追跡し、状態の変化を DragSourceListener
に配布する役割を果たします。
DragSourceContext
クラスは、次のように定義されます。
public class DragSourceContext implements DragSourceListener { public DragSourceContext( DragSourceContextPeer dscp, DragGestureEvent trigger, Cursor dragCursor, Image dragImage, Point dragOffset, Transferable transferable, DragSourceListener dsl ); public DragSource getDragSource(); public Component getComponent(); public DragGestureEvent getTrigger(); public Image getDragImage(); public Point getDragImageOffset(); public void transferablesFlavorsChanged(); public int getSourceActions(); public Cursor getCursor(); pbulic void setCursor(Cursor Cursor) throws InvalidDnDOperationException; public void addDragSourceListener(DragSourceListener dsl) throws TooManyListenersException; public void removeDragSourceListener(DragSourceListener dsl); protected updateCurrentCursor(int dropOperation, int targetActions, int status ); // values for status parameter above. protected static final int DEFAULT = 0; protected static final int ENTER = 1; protected static final int OVER = 2; protected static final int CHANGED = 3; //... }
DragSourceContext
自体が DragSourceListener
を実装することに注目してください。これにより、DragSource
によって作成されたプラットフォームのピアである DragSourceContextPeer
のインスタンスは、DragSourceContext
に進行中の操作状態の変化について通知できるようになります。したがって DragSourceContext
は、プラットフォームと、操作のイニシエータによって提供された DragSourceListener
の間に割り込むことができるようになります。
転送元、またはドラッグ&ドロップ操作のイニシエータに関してプラットフォームが公開する状態の変化の詳細は、次のとおりです。
ドラッグ&ドロップ操作中のイニシエータに関する状態の変化の通知は、上に示したように、DragSourceContextPeer
から適切な DragSourceContext
に配布されます。DragSourceContext は通知を、ユニキャスト JavaBeans に準拠した EventListener
サブインタフェースを介して、startDrag
で DragSource
に登録された DragSourceListener
を実装する任意のオブジェクトに委譲します。
DragSourceListener
のプライマリの役目は、ドラッグ&ドロップ操作中にユーザー操作の進行を監視して、Drag-Over 効果をユーザーにフィードバックすることです。一般的に、フィードバックは、Drag Cursor を変更することで行われます。
各ドラッグ操作には、次の 2 種類の論理カーソル (ドラッグカーソル) の状態が関連付けられています。
Cursor
。有効な DropTarget
上にドラッグしているときに表示されるカーソル。Cursor
。それ以外のものの上にドラッグしているときに表示されるカーソル (ドラッグ開始時のカーソルの初期状態)。Cursor
の状態は、DragSourceContext
の setCursor
メソッドを呼び出すことによって変更できます。
DragSourceListener
インタフェースは、次のように定義されます。
public interface java.awt.dnd.DragSourceListener extends java.util.EventListener { void dragEnter (DragSourceDragEvent dsde); void dragOver (DragSourceDragEvent dsde); void dropActionChanged (DragSourceDragEvent dsde); void dragExit (DragSourceEvent dse); void dragDropEnd (DragSourceDropEvent dsde); }
ドラッグ操作が進行するに従って、DragSourceListener
の dragEnter
、dragOver
、および dragExit
メソッドが呼び出されます。これは、DropTarget
が関連付けられている GUI Component
のジオメトリに交差するように、論理 Drag カーソルの位置をユーザーがナビゲートした結果です (DropTarget
のプロトコルの相互作用に関する詳細は次を参照)。
DragSourceListener
の dragEnter
メソッドは、次の条件が満たされたときに呼び出されます。
Component
の可視ジオメトリに最初に交わった。Component
に、アクティブな DropTarget
が関連付けられている。DropTarget
に登録された DropTargetListener
dragEnter
メソッドが呼び出され、正常に処理を返す。
登録された DropTargetListener
が、DropTargetDragEvent
の acceptDrag
メソッドを呼び出して、転送元が実行する可能性のあるドロップアクション、および利用可能なデータ型 (DataFlavors
) を調べた上で、ドラッグを受け入れます。
DragSourceListener の dragOver
メソッドは、次の条件が満たされたときに呼び出されます。
dragEnter
の呼び出しに関連付けられた Component
の可視ジオメトリに、まだ交差している。Component
に、DropTarget
が関連付けられている。DropTarget
がまだアクティブである。DropTarget
に登録された DropTargetListener
dragOver
メソッドが呼び出され、正常に処理を返す。DropTarget
が、rejectDrag
を介してドラッグ拒否しない。DragSourceListener
の dragExit
メソッドは、次の条件のうちの 1 つが満たされたときに呼び出されます。
dragEnter
の呼び出しに関連付けられた Component
の可視ジオメトリと、もはや交差していない。
または:
Component
(これが直前の dragEnter
の呼び出しにつながった) に、アクティブな DropTarget
(または DropTargetListener
) が関連付けられていない。
または:
dragEnter
または dragOver
が最後に呼び出されてから、現在の DropTarget
の DropTargetListener
が rejectDrag
を呼び出した。DragSourceListener
の dropActionChanged()
メソッドは、ドラッグ操作を実行するためにユーザーが使用している、マウスボタンやキーボードのキーなどの入力デバイスの状態が変わったときに呼び出されます。
dragDropEnd()
メソッドは、操作が完了したことを示すために呼び出されます。DragSourceDropEvent
の getDropSuccess
メソッドは、終了状態を確認するために使用されます。getDropAction
メソッドは、DropTarget
が DropTargetDropEvent
の acceptDrop
パラメータを介してドロップ操作に適用するために選択した操作を返します。
このメソッドが完了すると、現在の DragSourceContext
および関連付けられたリソースが無効になります。
DragSourceEvent
クラスは、DragSource
に属するすべてのイベントのルート Event
クラスで、次のように定義されています。
public class java.awt.dnd.DragSourceEvent extends java.util.EventObject { public DragSourceEvent(DragSourceContext dsc); public DragSourceContext getDragSourceContext(); //... };
このイベントのインスタンスは、DragSourceListener
の dragExit
メソッドに渡されます。
DragSourceDragEvent
クラスは、次のように定義されます。
public class java.awt.dnd.DragSourceDragEvent extends DragSourceEvent { public int getTargetActions(); public int getUserAction(); public int getGestureModifiers(); public int getGestureModifiersEx(); public int getDropAction(); }
このクラスのインスタンスは、DragSourceListener
の dragEnter
、dragOver
、および dragGestureChanged
の各メソッドに渡されます。
getDragSourceContext
メソッドは、現在のドラッグ&ドロップ操作に関連付けられた DragSourceContext
を返します。
getUserAction
メソッドは、ユーザージェスチャーによって現在選択されているアクションを返します。
getTargetActions
メソッドは、ドロップアクションがドラッグソースによってサポートされている場合には、現在のドロップターゲットにより選択されているドロップアクションを返し、ドロップアクションがドラッグソースによりサポートされていない場合には DnDConstants.ACTION_NONE
を返します。
これら 2 つの結果とドラッグソースによりサポートされる一連のドロップアクションの論理的な相互作用が、ドロップによる実際の効果を定義し、getDropAction
を介して返されます。
getGestureModifiers
メソッドは、入力デバイスの修飾子の現在の状態を返します。通常、入力デバイスの修飾子は、ユーザーのジェスチャーに関連付けられたマウスボタンおよびキーボードのキーです。
getGestureModifiersEx
メソッドは、ユーザーのジェスチャーに関連付けられた入力デバイスの拡張修飾子の現在の状態を返します。
DragSourceDropEvent
クラスは、次のように定義されます。
public public class java.awt.dnd.DragSourceDropEvent extends java.util.EventObject { public DragSourceDropEvent(DragSourceContext dsc); public DragSourceDropEvent(DragSourceContext dsc, int action, boolean success); public boolean getDropSuccess(); public int getDropAction(); }
このクラスのインスタンスは、DragSourceListener
の dragDropEnd
メソッドに渡されます。このイベントはドラッグ&ドロップ操作の終了状態を DragSource
のためにカプセル化します。
ドロップが発生して、ドロップに関係した DropTarget
が DropTargetContext
の dropComplete
メソッドを介してデータ転送の成功または失敗を示し、イニシエータは getDropSuccess
メソッドを介してこのステータスを取得できます。ドロップ先である DropTarget
がドラッグの対象に対して実行する操作は、(DropTarget
の acceptDrop
メソッドにより渡された) getDropAction
メソッドを介して返されます。
ユーザーが DropTarget
の外部でジェスチャーを終了するか、DropTarget
が rejectDrop
を呼び出した場合など、何らかの理由でドロップが発生する前にドラッグ操作が中止された場合は、getDropSuccess
メソッドは false を返します。そうでない場合は true を返します。
java.awt.Component
クラスには、DropTarget
との関連付けおよび関連付け解除を可能にするために、2 つのメソッドが追加されました。特に次の点が重要です。
public class java.awt.Component /* ... */ { //... public synchronized void setDropTarget(DropTarget dt); public synchronized DropTarget getDropTarget(DropTarget df); //... }
DropTarget
を Component
に関連付けるには、DropTarget.setCompononent
または Component.setDropTarget
のどちらのメソッドを呼び出すこともできます。このため、相互再帰呼び出しを防ぐために、両方のメソッドの実装に準拠する必要があります。
DropTarget
と Component
の関連付けを解除するには、DropTarget.setCompononent(null)
または Component.setDropTarget(null)
のどちらのメソッドを呼び出すこともできます。
DropTarget
と Component
の両方の設定メソッドの仕様に準拠する実装は、互いの状況を適切に管理するように実装する必要があります。
DropTarget
の実パラメータが Component
の、このクラスまたはインスタンスとともに使うことが不適切な場合は、setDropTarget
メソッドは、IllegalArgumentException
をスローします。また、Component
が DropTarget
の外部設定をサポートしていない場合なども、このメソッドは UnsupportedOperationException
をスローします。
DropTarget
は、操作の受け側または送り先の役割に関連する、ドラッグ&ドロッププロトコルのプラットフォーム固有の処理をすべてカプセル化します。
一般に、単一の DropTarget
インスタンスを、java.awt.Component
の任意のインスタンスに関連付けることができます。このような関係を確立すると、関連付けられた Component
の可視ジオメトリに論理カーソルの座標が交差したときに、ドラッグ&ドロップ操作の受け取りが可能であるとして、このジオメトリがクライアントのデスクトップにエクスポートされます。
DropTarget
クラスは、次のように定義されます。
public class java.awt.dnd.DropTarget implements DropTargetListener, Serializable { public DropTarget(Component c, int actions, DropTargetListener dsl, boolean isActive, FlavorMap fm ); public DropTarget(); public DropTarget(Component c); public DropTarget(Component c, DropTargetListener dsl); public Component getComponent(); public void setComponent(Component c); public DropTargetContext getDropTargetContext(); public void addDropTargetListener(DropTargetListener dte) throws TooManyListenersException; public void removeDropTargetListener(DropTargetListener dte); public void setActive(boolean active); public boolean isActive(); public FlavorMap getFlavorMap(); public void setFlavorMap(FlavorMap fm); public void setDefaultActions(int actions); public int getDefaultActions(); protected DropTargetContext createDropTargetContext(); public void addNotify(ComponentPeer cp); public void removeNotify(ComponentPeer cp); // ... }
Component
の実パラメータが DropTarget
の、このクラスまたはインスタンスとともに使うことが不適切な場合は、setComponent
メソッドは、IllegalArgumentException
をスローします。また、このメソッドは、Component
で、DropTarget
の外部設定を許可しないように指定されてる場合には、UnsupportedOperationException
をスローします。
addDropTargetListener
および removeDropTargetListener
メソッドを使って、ユニキャスト DropTargetListener
を変更できます。
setActive
および isActive
メソッドを使って、DropTarget
をアクティブまたは非アクティブにすることができ、さらに DropTarget の現在の状態を知ることができます。
getFlavorMap
メソッドは、プラットフォームに依存した型名と、それに対応するプラットフォームに依存しない DataFlavors
との間のマッピングを行う目的で、この DropTarget
に関連付けられた FlavorMap
を取得するために使います。
setFlavorMap
メソッドは、新しい FlavorMap
を DropTarget
に割り当てます。パラメータに null が指定された場合は、「デフォルト」の FlavorMap
を DropTarget
にインストールします。
createDropTargetContext
メソッドは、ドラッグ操作で最初に DropTarget
に関連付けられた Component
を検出したときに、背後のプラットフォームに依存したピアに、新しい DropTargetContext
のインスタンスを提供するためだけに呼び出されます。現在 DropTarget
に関連付けられている DropTargetContext
がない場合は、getDropTargetContext
の呼び出しに許可されている副作用によって、新しい DropTargetContext
のインスタンスが生成されます。
addNotify
および removeNotify
メソッドは、Component
の ComponentPeer
への関連付け (および関連付けの解除) を DropTarget
に通知するためだけに、Component
から呼び出されます。
DropTarget
自体が DropTargetListener
を実装することに注目してください。これにより、プラットフォームによって作成されたプラットフォームのピアである DropTargetContextPeer
のインスタンスは、DropTarget
に進行中の操作状態の変化について通知できるようになり、したがって DropTarget
は、プラットフォームと DropTarget
に登録されている DropTargetListener
の間に割り込むことができるようになります。
進行中のドラッグ&ドロップ操作に関連付けられた論理カーソルが、DropTarget
に関連付けられた Component
の可視ジオメトリと最初に交差すると、DropTarget
に関連付けられた DropTargetContext
がインタフェースになります。このインタフェースを介して、DropTargetListener
から受け側のプロトコルの状態を制御したりアクセスしたりできます。
DropTarget
の <>DropTargetContext が存在しない場合は、DropTarget
の getDropTargetContext
メソッドが呼び出されたときに、副作用として DropTarget
の createDropTargetContext
メソッドによって DropTargetContext
が作成されます。
DropTargetContext
インタフェースは、次のように定義されます。
public class DropTargetContext { public DropTarget getDropTarget(); public Component getComponent(); public void dropComplete(boolean success) throws InvalidDnDOperationException; public void acceptDrag(int dropAction); public void rejectDrag(); public void acceptDrop(int dropAction); public void rejectDrop(); public void addNotify(DropTargetContextPeer dtcp); public void removeNotify(); protected Transferable createTransferableProxy(Transferable t, boolean isLocal ); protected void setTargetActions(int actions); protected int getTargetActions(); protected DataFlavor[] getCurrentDataFlavors(); protected List getCurrentDataFlavorsAsList(); protected boolean isDataFlavorSupported(DataFlavor df); protected Transferable getTransferable(); // ... }
アクセスおよび制御を行うメソッドは、ほとんどが protected メソッドです。これらのメソッドの状態に public アクセスするときは、通常、要求を DropTargetContext
に委譲する特定の DropTargetEvent
サブクラスの呼び出しにより行います。
getDropTarget()
メソッドは、この DropTargetContext
を作成した DropTarget
を返します。
getComponent
メソッドは、この DropTargetContext
を作成した DropTarget
に関連付けられた Component
を返します。
acceptDrag
メソッドは、DropTargetDragEvent
の類似のメソッドから委譲されていて、DropTargetListener
のメソッド dragEnter()
、dragOver
、または dropActionChanged
から呼び出されます。acceptDrag の呼び出しは、受け側では指定された操作を含むドロップの受け取りの準備ができていることを意味します。通常は、現在ユーザーが選択しているアクションが操作として指定されます。
rejectDrag
メソッドは、DropTargetDragEvent
の類似のメソッドから委譲されていて、DropTargetListener
のメソッド dragEnter
、dragOver
、または dropActionChanged
から呼び出されます。rejectDrag の呼び出しは、現在ユーザーが選択しているアクションを受け取れないことを意味します。
acceptDrop
メソッドは、DropTargetDropEvent
の類似のメソッドから委譲されていて、DropTargetListener
の drop
メソッドから呼び出されます。acceptDrop の呼び出しは、受け側では指定された操作を含むドロップの受け取りの準備ができていることを意味します。通常は、現在ユーザーが選択しているアクションが操作として指定されます。
rejectDrop
メソッドは、DropTargetDropEvent
の類似のメソッドから委譲されていて、DropTargetListener
の drop
メソッドから呼び出されます。rejectDrop の呼び出しは、受け側では現在ユーザーが選択しているアクションを含むドロップの受け取りが不可能であることを意味します。このメソッドにより、ドラッグ&ドロップ操作が終了し、データは転送されません。
dropComplete
メソッドは、DropTargetListener
がドラッグ&ドロップ操作の対象を含む転送を完了したこと、および操作が完了したことを、転送元の DragSource
に通知します。転送の成功 (または失敗) および指定されたオペレーションのそれ以降の適用が、実際のパラメータの値によって通知されます。
getDataFlavors
メソッドは、DragSource
で利用できる DataFlavors
の配列を返します。
getTransferable
メソッドは、Transferable
を返し、getTransferData
メソッドを介したデータ転送を可能にします。返される Transferable は、必ずしも DragSource
が登録したものではなく、プロキシの可能性もあります (JVM 間の転送ではプロキシ)。最初に acceptDrop
を呼び出さずに getTransferable
を呼び出すことは不正です。
addNotify
および removeNotify
メソッドは、基本的なプラットフォームの DropTargetContextPeer
によって排他的に呼び出され、DropTargetContext
およびそれと関連付けられた DropTarget
で発生または終了したドラッグ&ドロップ操作を DropTargetContext
に通知します。
createTransferableProxy
メソッドにより、DropTargetContext
の実装で、DropTargetListener
と呼び出し元から提供された Transferable
との間に Transferable
を挿入できるようになります。一般に、呼び出し元は基本的なプラットフォームの DropTargetContextPeer
です。
適切な Drag-under フィードバックセマンティクスの提供、およびその後のドロップの処理は、DropTarget
に関連付けられた DropTargetListener
を使って可能になります。
DropTargetListener
は、転送元によって提案されたアクション、利用可能なデータ型、およびデータ自体を検査することによって、ドロップが可能かどうかに関する適切な Drag-under フィードバックおよび DragSource
への応答を決定します。
特定の DropTargetListener
インスタンスは、addDropTargetListener
メソッドを介して DropTarget
に関連付けられ、removeDropTargetListener
メソッドを介して削除されます。
public interface java.awt.dnd.DropTargetListener extends java.util.EventListener { void dragEnter (DropTargetDragEvent dtde); void dragOver (DropTargetDragEvent dtde); void dropActionChanged (DropTargetDragEvent dtde); void dragExit (DropTargetDragEvent dtde); void drop (DropTargetDropEvent dtde); }
DropTargetListener
の dragEnter
メソッドは、論理 Drag カーソルのホットスポットが、DropTarget
に関連付けられた Component
のジオメトリの可視部分と交差したときに呼び出されます。この通知を受け取ると、DropTargetListener
は、DragSource
から提供される操作またはアクション、あるいはデータ型 (DataFlavors
) およびデータ自体を調べて、適切なアクションおよび Drag-under フィードバックを決定し、acceptDrag
または rejectDrag
を呼びます。
DropTargetListener
の dragOver
メソッドは、動いている論理 Drag カーソルのホットスポットが、DropTarget
に関連付けられた Component
のジオメトリの可視部分と交差し続けている間に呼び出されます。この通知を受け取ると、DropTargetListener
は、DragSource
から提供されるアクション、およびデータ型あるいはデータ自身を調べて、適切なアクションおよび Drag-under フィードバックを決定し、acceptDrag
または rejectDrag
を呼び出します。
DropTargetListener
の dragExit
メソッドは、論理 Drag カーソルのホットスポットが、DropTarget
に関連付けられた Component
のジオメトリの可視部分と交差しなくなったとき、または drop
による通知が行われる直前に呼び出されます。この通知を受け取ると、DropTargetListener
は、それまでに適用したすべての Drag-under フィードバック効果を取り消します。このときの副作用として、DropTarget
に関連付けられた DropTargetContext
が無効になることに注意してください。
交差している間にユーザーがドラッグジェスチャーを終了すると、DropTargetListener
の drop
メソッドが呼び出されます。この通知を受け取ると、DropTargetListener
は、DropTargetDropEvent
オブジェクト上の getSourceActions
メソッドの戻り値によって指定された操作を、getTransferable
メソッドから返された Transferable
オブジェクト上で実行します。その後、関連付けられた DropTargetContext
の dropComplete
メソッドを呼び出して、操作の成功または失敗を示します。
DropTargetEvent
および DropTargetDragEvent
は次のように定義されています。
public abstract class java.awt.dnd.DropTargetEvent extends java.util.EventObject { public DropTargetContext getDropTargetContext(); //... }
DropTargetEvent
は、DropTargetListener
の dragExit
メソッドに渡されます。
public class java.awt.dnd.DropTargetDragEvent extends java.awt.dnd.DropTargetEvent { public Transferable getTransferable(); public Point getLocation(); public int getSourceActions(); public getDropAction(); public DataFlavor[] getCurrentDataFlavors(); public List getCurrentDataFlavorsAsList(); public boolean isDataFlavorSupported(); public void acceptDrag(int operation); public void rejectDrag(); //... }
DropTargetDragEvent
は、DropTargetListener
の dragEnter
、dragOver
、および dropActionChanged
メソッドに渡されます。
getLocation
メソッドは、関連付けられた Component
を原点として、論理 Drag カーソルのホットスポットの現在の相対座標を返します。
getSourceActions
メソッドは、現在の「アクション」、つまり DragSource
によって現在のドラッグ&ドロップのジェスチャーに関連付けられた操作 (ACTION_MOVE、ACTION_COPY、または ACTION_REFERENCE) を返します。
getDropAction
メソッドの戻り値は、ユーザージェスチャーによって現在選択されているアクションを返します。
getCurrentDataFlavors
、getCurrentDataFlavorsAsList
、および isDataFlavorSupported
メソッドは、転送元のリスト型を受け側で調べるときに使用します。
getTransferable
メソッドは、転送元のデータを受け側で調べるときに使用します。DropTargetDragEvent
インスタンス上の getTransferable
はそれぞれの DropTargetListener
のメソッド内でのみ呼び出され、すべての必要なデータはメソッドが返される前に、返された Transferable
から取り出されることに注目してください。
DropTargetDropEvent
は、次のように定義されます。
public class java.awt.dnd.DropTargetDropEvent extends java.awt.dnd.DropTargetEvent { public Point getLocation(); public int getSourceActions(); public int getDropAction(); public void acceptDrop(int dropAction); public void rejectDrop(); public boolean isLocalTransfer(); public DataFlavor[] getCurrentDataFlavors(); public List getCurrentDataFlavorsAsList(); public boolean isDataFlavorSupported(DataFlavor df); public Transferable getTransferable(); public void dropComplete(boolean success); //... }
ドロップが発生すると、DropTargetDropEvent
が DropTargetListener
の drop
メソッドに渡されます。DropTargetDropEvent
は DropTargetListener
に対して、getTransferable
メソッドから返される Transferable
を介して、この操作に関連付けられたデータへのアクセスを提供します。
getSourceActions
メソッドの戻り値は、ドロップの発生時に転送元によって定義されたアクションを返すように定義されています。
getDropAction
メソッドの戻り値は、ユーザージェスチャーによって現在選択されているアクションを返します。
getLocation
メソッドの戻り値は、ドロップが発生した位置を返すように定義されています。
getCurrentDataFlavors
、getCurrentDataFlavorsAsList
、および isDataFlavorSupported
メソッドは、Transferable
の getTransferData
メソッドによって後続の転送が行われるときに、転送元のデータ型を受け側で調べるときに使用されます。
drop
メソッドの標準の実装は、アクションおよび利用可能な DataFlavor
を検査し、交換が正常に終了するかどうかを判定します。
交換が発生すると、DropTargetListener.drop
実装は、getTransferable
を呼び出す前に、選択された操作で実パラメータとして acceptDrop
を呼び出します。acceptDrop
の前に getTransferable
を呼び出すと、InvalidDnDOperationException
が発生します。
rejectDrop
を呼び出して、ドロップ操作を拒否することも可能です。rejectDrop を呼び出すと、転送元と受け側の間の対話が停止します。このため、通常は、rejectDrop を呼び出すと、ただちに drop
メソッドから戻ります。
ドラッグ&ドロップ操作の転送元が、drop
による通知の受け側と同一の物理 JVM に存在する場合は、isLocalTransfer
メソッドから true が返されます。同一の物理 JVM に存在しない場合は、false が返されます。
ローカルの物理 JVM で呼び出された Transferable.getTransferData
からオブジェクト参照を受け取る場合は、この違いが重要になります。この場合、受け取ったオブジェクト参照は、転送元で保持されているものと同じです (コピー、プロキシ、および異なるオブジェクトではない)。このため、受け側では共有オブジェクト参照を、次のような特別な方法で処理する必要があります。
dropCompete
が呼び出されて転送の完了が転送元に通知されるまで、オブジェクトまたはカプセル化されたデータの状態を変更できません。また、転送元は、getTransferData
メソッドからこれらのオブジェクトを返したあとでも、dragDropEnd
による通知を受け取るまで、オブジェクトの状態を変更できません。dropComplete
および dragDropEnd
メソッドが処理されるまでは、交換されたオブジェクトまたはそのオブジェクトに含まれるデータの状態を変更することはできません。その後、共有セマンティクスは、共有されているオブジェクトに依存した実装になります。dropComplete
メソッドは、関連付けられたドラッグ&ドロップ操作の終了を通知し、受け側で実行された転送の成功 (または失敗) を返します。このメソッドを呼び出すと、DragSourceListener
の dragDropEnd
メソッドが、DragSourceDropEvent
で使用できる適切な状態で呼び出されます。このメソッドの呼び出しに失敗すると、ドラッグ&ドロップ操作が正常に終了しません。
多くの GUI Component
は、大規模な (大規模になり得る) データセットに対し、スクロール可能な「ビューポート」を提供します。ドラッグ&ドロップ操作時には、これらのビューポートを自動スクロールできることが望ましいでしょう。そうすれば、操作の対象物をドロップしたい特定の (最初はビューポートに表示されていない) メンバーの位置までスクロールしながら、データセット上を移動することができます。
スクロール可能な Component
は、次のインタフェースを実装することによって、DropTarget
にドラッグの「自動スクロール」機能を提供します。
public interface Autoscroll { Insets getAutoscrollInsets(); void autoScrollContent(Point cursorLocn); }
次の条件が満たされた場合、実装する DropTarget
は、関連付けられた Component
(存在する場合) の autoscroll
メソッドを定期的に呼び出し、Component
の座標で表した現在の論理カーソルの位置を渡します。
Component
の可視ジオメトリ、および getAutoscrollInsets
メソッドが返す Insets
によって記述された境界領域と交差した場合。上のいずれかの条件が満たされなくなると、次にトリガーとなる条件が発生するまで自動スクロール機能は終了します。
自動スクロール開始前の初期遅延、自動スクロール通知の間隔、およびピクセルのヒステリシス値はすべて、外部で構成でき、Toolkit.getDesktopProperty
メソッドから問い合わせることができます。
有効なドロップが発生した場合は、DropTargetListener
の drop
メソッドは、ジェスチャーに関連付けられたデータの転送に取りかかります。DropTargetDropEvent
は、転送されるデータオブジェクトを表す Transferable
オブジェクトを取得するための手段を提供します。
まず、drop
メソッドにより、DropTargetListener
が、rejectDrop
を呼び出してドロップを拒否するか (この場合はすぐに復帰する)、または getSourceActions
によって返された操作から選択された操作を指定する acceptDrop
を呼び出してドロップを受け入れます。
acceptDrop
のあとは、getTransferable
が呼び出され、返された Transferable
の getTransferData
メソッドを介してデータ転送が行われます。最後に、ドロップの転送先で転送元からのオブジェクトの転送が完了すると、DropTargetContext.dropComplete
が呼び出され、転送の成功または即時失敗が通知されます。
DropTargetContext.dropComplete
メソッドから復帰すると同時に、Transferable
および DragSourceContext
のインスタンスが有効であるという保証がなくなるため、あとでガベージコレクトできるように、受け側によりインスタンスへのすべての参照が破棄されます。
ACTION_REFERENCE 操作を使う場合は、転送元と転送先でオブジェクトおよび関連付けられた転送のセマンティクスに合意が必要です。一般に、JVM 内の転送では、転送元と転送先の間でライブオブジェクト参照が渡されますが、JVM 間の転送、またはネイティブアプリケーションと Java アプリケーションの間では、ライブオブジェクト参照は無意味で、URI などのほかの種類の参照が交換されます。転送が JVM 内の転送かどうかは、DragSource
と DropTarget
の両方で検出できます。
ターゲットとなるすべてのドラッグ&ドロッププラットフォームは、同様のメカニズムを使って転送データの型を表しますが、この表現方法には違いがあります。Java プラットフォームでは、DataFlavor
内にカプセル化された MIME 形式を使ってデータ型を表します。Java と、プラットフォームにネイティブなアプリケーションとの間でのデータ転送を許可するには、これらのプラットフォーム名の存在が公開される必要があります。このため、これらのプラットフォームに依存する型名、それらの表現方法、および Java MIME ベースの DataFlavor
間で、プラットフォームに依存しない拡張可能なマッピングを作成するためのメカニズムが必要です。
この実装は、プラットフォームにネイティブなデータ型 (文字列) と DataFlavor
の構築に使われる MIME 形式 (文字列) との間のマッピングを外部で指定するメカニズムを提供します。この外部マッピングは、背後のプラットフォームのドラッグ&ドロップメカニズムによって転送元から転送先にエクスポートされる適切な DataFlavors
(MIME 形式) を公開するために、背後のプラットフォーム固有の実装コードで使われます。
背後のシステムは、DragSource
クラスおよび DropTarget
クラスのどちらを使っても、プラットフォームに依存する名前と DataFlavors
間のマッピングにアクセスできます。
public interface java.awt.datatransfer.FlavorMap { java.util.Map getNativesForFlavors(DataFlavor[] dfs); java.util.Map getFlavorsForNatives(String[] natives); }
getNativesForFlavors
メソッドは、DataFlavor
の配列をパラメータにとり、実パラメータ dfs
から、関連付けられた String
型の値 (その MIME 形式に対応するプラットフォームに依存する型名に一致) とともに、DataFlavor
型のゼロ個以上のキーを含む Map
オブジェクトを返します。
getFlavorsForNatives
メソッドは、String
型の配列をパラメータにとり、実パラメータ natives から、関連付けられた DataFlavor
型の値 (そのプラットフォームに依存する型名に対応するプラットフォームに依存しない型に一致) とともに、String
型のゼロ個以上のキーを含む Map
オブジェクトを返します。
これらのメソッドによって返される Map
オブジェクトは可変の場合もありますが、必ずしもその必要はありません。
null がこれらのメソッドのうちのいずれかに渡されると、呼び出しの時点で実装にとって既知であるすべてのキーと値の現在のマップが返されます。
たとえば、Win32 では、シンプルテキストのクリップボード形式の名前は、CF_TEXT (実際にはこれは整数 1) ですが、Motif では、STRING という名前の X11 Atom です。MIME 形式を使ってこれを表現する場合は、text/plain charset=us-ascii です。プラットフォームに対する移植性のある FlavorMap
は、Win32 上の CF_TEXT と Motif/X11 上の STRING 間のマッピングを行います。
一般に、これらのマッピングは、SystemFlavorMap
に実装するときに、外部の固定された構成形式 (プロパティーファイルまたは URL) に保持し、プラットフォームからロードして、特定のプラットフォームに適切に FlavorMap
を設定するようにします。
SystemFlavorMap
クラスは、全システムに共通なマッピングのセットを指定するための、プラットフォームで構成が可能な単純なメカニズムを実装するために提供されています。次のように定義されています。
public class java.awt.datatransfer.SystemFlavorMap implements FlavorMap, FlavorTable { public static FlavorMap getSystemFlavorMap(); public synchronized Map getNativesForFlavors(DataFlavor[] dfs); public synchronized Map getFlavorsForNatives(String[] natives); public static String encodeDataFlavor(DataFlavor flav); public static String encodeJavaMIMEType(String mimeType); public static boolean isJavaMIMEType(String mimeStr); public static String decodeJavaMIMEType(String nat); public static DataFlavor decodeDataFlavor(String nat); //... }
SystemFlavorMap
クラスは、プラットフォーム固有の FlavorMap
のプロパティーファイル (java.awt.Properties
を参照) を使った単純な実装を提供します。このクラスは、AWT のプロパティーである AWT.flavorMapFileURL (Toolkit.getProperty
を参照) の値か、または System.getProperty("java.home") + File.separator + "lib" + File.separator + "flavormap.properties"
のデフォルトのファイル位置を使って、そのプロパティーから適切な Map
を作成します。
さらに、このクラスは、Java MimeType
とプラットフォームに依存した名前空間のエンコードまたはデコードに使う、いくつかの static な簡易関数を提供します。プロパティーファイルの構文は、次のとおりです。
{ <platform_type_name> ‘=' <IETF_MIME_RFC_conformant_specification> <nl> } *
DragSource
および DropTarget
のデフォルト実装は、その他の実装によってオーバーライドされていなければ、getFlavorMap
メソッドから SystemFlavorMap
を返します。
この API では、Java とネイティブアプリケーションの間でデータをドラッグ&ドロップできることがプライマリの目標です。このことが、Java 仮想マシンの境界を越えてデータが渡されたときに行われる、実際のデータエンコードおよびデータ交換の方法およびメカニズムに大きく影響しています。
このようなデータ交換では、転送元または受け側が Java のデータ型を認識しないネイティブアプリケーションであるため、このドラッグ&ドロップのシステムでは単純に Java オブジェクトの参照を渡すことができません。転送元または受け側で Java のデータ型の認識または操作を行うことができない可能性があるためです。
データ交換が発生すると、転送元と受け側の実装に関係なく、データ型およびエンコードの方式に双方が合意しているときにかぎり、データ交換が実現されます。つまり残念なことに、交換で発生する問題は、ほとんどの場合、転送元および受け側のアプリケーションが原因です。
実質的には、プラットフォームに依存したイメージ、ドキュメント、その他の「Content-Type」など、「ネイティブ」なデータ形式の場合において、関連する外部形式のエンコードとデコードは、転送を行う転送元と転送先の責任によって行われます。
このドラッグ&ドロップシステムでは、そのような Java 仮想マシンの境界を越える「ネイティブ」なデータ型の外部表現が、java.io.InputStream
またはそのサブクラス内にカプセル化されて公開されます。
つまり、java.io.InputStream
を継承する表現クラスを含むすべての DataFlavor
が、Java 仮想マシンの境界を越えて転送可能であり、転送のために公開されることになります。
このようなネイティブなデータ型の交換を実装するには、DataFlavor
を MIME の「Content-Type」に定義します。MIME の「Content-Type」には、「ネイティブ」なデータ型の特性が、java.io.InputStream
クラスを継承する表現クラスを使って記述されています。java.io.InputStream クラスによって、カプセル化されたデータがバイトストリームにエンコードされます。
特に、このような InputStream
サブクラスによって、次のセマンティクスが実装されます。
java.io.InputStream
型の引数を 1 つ取る public コンストラクタの提供。
java.io.InputStream
のサブクラスによってこのコンストラクタが提供されるため、DropTarget
に関連付けられたドラッグ&ドロップシステムでは、要求された DataFlavor
に指定されている表現クラスのインスタンスが自動的に再構築されます。そのインスタンスは、サブクラスの要求に応じてフォーマットされたカプセル化データを含む InputStream
によって初期化されます。このインスタンスは、初期化されると、Transferable.getTransferData
メソッドの呼び出し側に返されます。次に、呼び出し側では、データストリームが転送されると、フォーマットされた内容が読み取られ解釈されます。
InputStream.read(byte b[], int off, int len)
の実装の提供。このメソッドの提供 (またはスーパークラス実装の継承) によって、DragSource
に関連付けられたドラッグ&ドロップシステムでは、カプセル化されたデータのエンコードされたストリームが Transferable
から自動的に抽出されます。この結果、このデータは JVM の境界を越えて、DataFlavor
のリクエスタに単純なバイトストリームとして転送されます。
ドラッグ&ドロップ転送の典型的な対象として、プラットフォームに依存する 1 つ以上のファイル名のリストを挙げることができます。ファイル名リストの作成または処理を行うプログラムを簡単に開発できるように、ドラッグ&ドロップシステムでは、ファイル名リストは独自に処理されます。
DataFlavor
が application/x-java-file-list;class=java.util.List
という MIME「Content-Type」に指定されている場合、ドラッグ&ドロップシステムでは、リストの要素が java.io.File
型のオブジェクトのリストと同質であることを前提としています。したがって、ファイルリストの転送がサポートされている場合は、この DataFlavor
が要求されると、転送元では、その File
オブジェクトの List
が構築されます。また、受け側が、有効な DataFlavor
を要求した場合は、その File
オブジェクトの List
を転送元から受け取ります。転送元とターゲット間でファイルリストを転送するときは、この独自の処理による簡単なメカニズムが使用されます。
RMI メカニズムの機能を使用すれば、JVM 間でオブジェクト参照をドラッグ&ドロップすることができます。ドラッグ&ドロップシステムでは、次の要件を満たすように、オブジェクト参照の転送が自動的に構成されます。
DataFlavor
に関連付けられたインタフェースの表現クラスが、java.rmi.Remote
と java.io.Serializable
の両方を実装している。
(MIME の「Content-Type」には、任意の適合したデータ型、または application/x-java-remote-object を指定できる)
(効果的に実装するには、転送されたオブジェクト実装クラスは、java.rmi.server.UnicastRemoteObject
から継承されていなければならない。RMI システムには必要な初期化がいくつか実装されているためである。その初期化が実装されていない場合は、転送は正常に完了しない)。
これらの条件が満たされている場合は、適切な DataFlavor
が要求されると、要求元 (転送元と異なる JVM に存在する場合) に返されるオブジェクトは、DataFlavor
の表現クラスとして指定されている Remote
オブジェクトサブインタフェースのインスタンスへの RMI 参照になります。
特定の基本的なプラットフォームのドラッグ&ドロップ、およびウィンドウシステムの実装には制限があるため、ドラッグ操作の対話、および AWT Component
へのイベント送信のセマンティクスは、プラットフォームに依存しています。このため、ドラッグ操作中に DragSource
がそのドラッグに属するプラットフォームのウィンドウシステムイベントの処理を行い、通常のイベント処理が排除されることがあります。
プラットフォームネイティブなドラッグ&ドロップシステムのシングルスレッドの処理部と、AWT 内の実装を担当するネイティブなウィンドウシステムイベントの対話により、DropTargetListener
、および DragSourceListener
への「コールバック」は、AWT システムイベントを処理するスレッド上か、またはスレッドと同期して発生します。これは、セキュリティーの面で望ましくない動作ですが、構造ではなく実装上の特徴なので、避けることができません。
JVM 内のドラッグ&ドロップ転送を可能にするため、既存の DataFlavor
クラスは、直列化された固定表現ではなく、「ライブ」オブジェクト参照の型を表現できるように拡張されます。このようなオブジェクトは、同じ JVM、および ClassLoader
コンテキスト内にある転送元と転送先の間で転送されます。
MIME コンテンツタイプは、application/x-java-local-objectref になります。
Transferable
オブジェクト、それに関連付けられた DataFlavor
、およびドラッグ&ドロップ操作のオペランドに指定された基本的なデータをカプセル化するオブジェクトは、少なくとも、操作を制御する DragSource
に関連付けられた DragSourceListener
が dragDropEnd
イベントを受け取るまで有効です。転送元と転送先の間での操作対象のライフタイムは、その時点を過ぎて定義される実装です。
正常に終了したドラッグ&ドロップ (ACTION_MOVE) 操作の「転送元」は、転送が正常に完了したあと、すぐに Transferable
の対象であるオブジェクトへの参照を削除または放棄する必要があります。これは、DragSourceListener.dragDropEnd
通知から戻る前に行う必要があります。
以前のバージョンの仕様に対する開発者からのフィードバックの結果、動作タグ ACTION_REFERENCE が追加されました。このタグにより、既存のプラットフォームのドラッグ&ドロップ「リンク」セマンティクスを含めることができます。
参照、つまりリンクのセマンティクスは、プラットフォームネイティブのドラッグ&ドロップにとって非常に不都合なものであるため、ネイティブなアプリケーション間でさえも本質的に使い物にならなくなっていると言えます。このため、ネイティブと、プラットフォームに依存しない Java アプリケーションとの間では、このセマンティクスの使用は推奨されません。
Java 対 Java で使用する場合、求められるセマンティクス (同一の JVM および ClassLoader
内) は、転送先が転送対象への Java オブジェクト参照を取得するように定義されています。JVM または ClassLoader
間では、セマンティクスの実装は定義済みですが、転送元から転送先に URL を送るか、RMI Remote
参照によって実装することもできます。
この定義は、この仕様の標準的な部分ではありませんが、仕様をわかりやすくするために含められています。
public interface DropTargetPeer { void addDropTarget(DropTarget dt); void removeDropTarget(DropTarget dt); }
この定義は、この仕様の標準的な部分ではありませんが、仕様をわかりやすくするために含められています。
public interface DragSourceContextPeer { void startDrag(DragSourceContext dsc, Cursor c, Image di, Point ioff ) throws InvalidDnDOperationException; Cursor getCursor(); void setCursor(Cursor c) throws InvalidDnDOperationException; void transferablesFlavorsChanged(); }
この定義は、この仕様の標準的な部分ではありませんが、仕様をわかりやすくするために含められています。
public interface DropTargetContextPeer { int getTargetActions(); void setTargetActions(int actions); DropTarget getDropTarget(); DataFlavor[] getTransferDataFlavors(); Transferable getTransferable() throws InvalidDnDOperationException; boolean isTransferableJVMLocal(); void acceptDrag(int dragAction); void rejectDrag(); void acceptDrop(int dropAction); void rejectDrop(); void dropComplete(boolean success); }