印刷ビューの終了

Java SE 7 デスクトップテクノロジのトラブルシューティングガイド

印刷ビュー

ドキュメント情報

はじめに

1. はじめに

2. AWT

2.1 AWT のデバッグに関するヒント

2.2 レイアウトの問題

2.3 キーイベント

2.3.1 未解決の一般的なキーボード問題

2.3.2 Linux および Solaris 10 OS x86 のキーボード問題

2.4 モーダリティー

2.4.1 UNIX のウィンドウマネージャー

2.4.2 アプレットからのモーダルダイアログの使用

2.4.3 モーダルのその他の問題

2.5 メモリーリーク

2.5.1 メモリーリークのトラブルシューティング

2.5.2 メモリーリークの問題

2.6 クラッシュ

2.6.1 AWT のクラッシュを判別する方法

2.6.2 AWT のクラッシュをトラブルシューティングする方法

2.7 フォーカスの問題

2.7.1 フォーカスイベントをトレースする方法

2.7.2 ネイティブフォーカスシステムとの通信

2.7.3 プラグインでのフォーカスシステム

2.7.4 X ウィンドウマネージャーでサポートされているフォーカスモデル

2.7.5 その他のフォーカス問題

2.8 ドラッグ&ドロップ

2.8.1 ドラッグ&ドロップアプリケーションのデバッグ

2.8.2 ドラッグ&ドロップのよくある問題

2.9 その他の問題

2.9.1 スプラッシュ画面の問題

2.9.2 トレイアイコンの問題

2.9.3 ポップアップメニューの問題

2.9.4 バックグラウンド/フォアグラウンドカラーの継承

2.9.5 AWT パネルのサイズ制限

2.9.6 X11 上でポップアップメニューや類似コンポーネントをデバッグする際にハングアップする

2.9.7 X11 での Window.toFront()/toBack() の動作

2.10 重量/軽量コンポーネントの混在

2.10.1 コンポーネント階層の有効化の要件

2.10.2 有効なルート

2.10.3 Swing のペイントの最適化

2.10.4 不透明でない軽量コンポーネント

2.10.5 デフォルトの HW/LW 混在機能実装の無効化

3. Java 2D

4. Swing

5. 国際化

6. Java Sound

7. アプレットと Java Web Start アプリケーション

8. バグレポートの送信

A. Java 2D のプロパティー

B. 致命的エラーログ

第 2 章

AWT

この章では、Java SE AWT API で発生する可能性のあるもっとも一般的な問題のいくつかをトラブルシューティングするための、具体的な手順に関する情報と指針を提供します。

2.1 AWT のデバッグに関するヒント

AWT のデバッグ時に役立つ可能性のあるヒントを次に示します。

Java SE 7 より前は、AWT のイベントディスパッチスレッド (EDT) でスローされた例外をキャッチするには、システムプロパティー sun.awt.exception.handlerpublic void handle(Throwable) メソッドを実装したクラスの名前を設定していました。Java SE 7 ではこのメカニズムが更新され、標準の Thread.UncaughtExceptionHandler インタフェースが使用されるようになりました。

AWT の問題をデバッグする際には、ロガーによって生成される出力が役立ちます。ロガーの使用方法については、「Java ロギングの概要」や java.util.logging パッケージの説明を参照してください。

使用可能なロガーは次のとおりです。

2.2 レイアウトの問題

このセクションでは、発生する可能性のあるいくつかのレイアウト問題について説明し、回避方法がある場合はその方法を提供します。

問題: invalidate()validate() を呼び出すと、コンポーネントのサイズが増えます。

原因: レイアウトマネージャー GridBagLayout のある特性のために、ipadx または ipady が設定された状態で invalidate()validate() が呼び出されると、コンポーネントのサイズが ipadx または ipady の値まで増えます。その理由は、コンテナ内にコンポーネントを格納するために必要な領域の量を、レイアウトマネージャー GridBagLayout が繰り返し計算するからです。

回避方法: JDK には、そのような場合にレイアウトマネージャーがコンポーネントを配置し直すべきかどうかを検出するための信頼できる単純な方法は用意されていませんが、非常に単純な回避方法があります。getPreferredSize() メソッドをオーバーライドしたコンポーネントを使用してください。このメソッドは常に現在の必要サイズを返します。

public Dimension getPreferredSize(){
   return new Dimension(size+xpad*2+1, size+ypad*2+1); 
}
問題: Container.doLayout() メソッドから validate() を呼び出したときの無限再帰。

原因: Container.doLayout() メソッドから validate() を呼び出すと、AWT 自身が validate() から doLayout() を呼び出すため、無限再帰が発生する場合があります。

2.3 キーイベント

このセクションではキーイベントの問題について説明します。

2.3.1 未解決の一般的なキーボード問題

現在解決されていないキーボードの問題は、次のとおりです。

2.3.2 Linux および Solaris 10 OS x86 のキーボード問題

Linux および Solaris 10 OS x86 システムに関係するキーボードの問題を次に示します。

2.4 モーダリティー

Java SE 6 リリースでは、AWT モーダリティーの領域で多くの問題が解決され、多くの改善が実装されました。Java SE 1.5 以前のリリースでモーダリティーの問題が発生している場合は、まず最新の Java SE リリースにアップグレードし、問題がすでに修正されているか確認してください。Java SE 6 で修正された問題のいくつかを次に示します。

2.4.1 UNIX のウィンドウマネージャー

一部の Solaris OS または Linux 環境 (CDE ウィンドウマネージャーを使用する場合など) では、モーダリティーの改善点の多くは使用できません。Java SE 6 以降で、あるモーダリティータイプやモーダル除外タイプが特定の構成でサポートされているかどうかを確認するには、メソッド Toolkit.isModalityTypeSupported() および Toolkit.isModalExclusionTypeSupported() を使用します。

Solaris OS または Linux で Java モーダルダイアログを実行する場合に別の問題があります。モーダルダイアログが画面に表示される際に、ウィンドウマネージャーによって、同じアプリケーション内のトップレベルの Java ウィンドウのいくつかがタスクバーに表示されなくなる場合があります。これによってエンドユーザーが困惑する可能性もありますが、ユーザーの作業にはさほど影響はありません。非表示になったウィンドウはすべてモーダルブロックの状態になっており、操作できないからです。

2.4.2 アプレットからのモーダルダイアログの使用

アプリケーションをブラウザ内のアプレットとして実行してモーダルダイアログを表示した場合、ブラウザのウィンドウがブロックされる可能性があります。このブロック処理の実装は、ブラウザやオペレーティングシステムごとに異なります。たとえば、Windows では Internet Explorer と Mozilla はどちらも正しく動作しますが、Solaris OS や Linux では Mozilla のウィンドウはブロックされません。これは将来のリリースで修正される予定です。

2.4.3 モーダルのその他の問題

Java SE 7 向けの AWT モーダリティードキュメントでは、モーダリティー関連の機能とその使用方法について説明しています。このドキュメントのセクションの 1 つでは、モーダルダイアログに関係したりその影響を受けたりする可能性のある領域 (常時最前面プロパティー、フォーカス処理、ウィンドウ状態など) をいくつか説明しています。そのような場合のアプリケーションの動作は通常、未定義となるかプラットフォームに依存するので、特定の動作をあてにしないでください。

2.5 メモリーリーク

このセクションではまず、メモリーリークのトラブルシューティングの方法について説明します。その後、考えられるメモリーリークの原因をいくつか示し、回避方法を説明します。

2.5.1 メモリーリークのトラブルシューティング

メモリーリークの詳細情報を得るには、java の実行時にヒーププロファイラをアクティブにします。jhat ユーティリティーを使って出力を読み取れるように、出力をバイナリ形式で生成するよう指定します。

$ java -agentlib:hprof=file=snapshot.hprof,format=b application

メモリーリークのトラブルシューティングの詳細情報や、jhat ユーティリティーやその他の使用可能なトラブルシューティングツールの説明については、HotSpot VM に関する Java SE 7 向けのトラブルシューティングガイドを参照してください。

2.5.2 メモリーリークの問題

問題: アプリケーション内でのメモリーリーク。

原因: フレームやダイアログのガベージコレクションが行われないときがあります。このバグは Java SE の将来のバージョンで修正される予定です。

回避方法: 既知のメモリーリークは、あるフォーカス可能なトップレベル要素 (ウィンドウ、ダイアログ、フレーム) へのフォーカス移動がシステムによって開始されたが、フォーカス移動が完了する前にその要素がクローズ、非表示化、または破棄されてしまった場合に発生します。したがってアプリケーションは、フォーカス移動操作が完了するまで待ってから要素のクローズ、非表示化、または破棄を行う必要があります。

この問題は通常、これらのアクションがプログラム経由で実行される場合にのみ発生します。通常、問題が発生する速度でユーザーがこれらのアクションを実行することは、身体的に不可能だからです。

2.6 クラッシュ

このセクションでは、クラッシュが AWT に関係するかどうかを判断する方法や、そのようなクラッシュをトラブルシューティングする方法を説明します。

2.6.1 AWT のクラッシュを判別する方法

クラッシュが発生すると、致命的エラーの発生時に取得された情報や状態を含むエラーログが作成されます。このログファイルの詳細については、「付録 B: 致命的エラーログ」を参照してください。

このファイルの先頭付近の行には、エラーが発生したライブラリが示されます。下の例では、クラッシュが AWT ライブラリに関係していたことがわかります。

...
# Java VM: Java HotSpot(TM) Client VM (1.6.0-beta2-b76 mixed mode, sharing)
# Problematic frame:
# C  [awt.dll+0x123456]
...

ただし、システムライブラリ内のどこか深い場所でクラッシュが発生しても、その原因がやはり AWT である場合もあります。その場合、awt.dll という目印は、問題のあるフレームとしては現れないため、ファイル内のセクション Stack: Native frames: Java frames をさらに確認する必要があります。次に例を示します。

Stack: [0x0aeb0000,0x0aef0000),  sp=0x0aeefa44,  free space=254k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C  0x00abc751
C  [USER32.dll+0x3a5f]
C  [USER32.dll+0x3b2e]
C  [USER32.dll+0x5874]
C  [USER32.dll+0x58a4]
C  [ntdll.dll+0x108f]
C  [USER32.dll+0x5e7e]
C  [awt.dll+0xec889]
C  [awt.dll+0xf877d]
j  sun.awt.windows.WToolkit.eventLoop()V+0
j  sun.awt.windows.WToolkit.run()V+69
j  java.lang.Thread.run()V+11
v  ~StubRoutines::call_stub
V  [jvm.dll+0x83c86]
V  [jvm.dll+0xd870f]
V  [jvm.dll+0x83b48]
V  [jvm.dll+0x838a5]
V  [jvm.dll+0x9ebc8]
V  [jvm.dll+0x108ba1]
V  [jvm.dll+0x108b6f]
C  [MSVCRT.dll+0x27fb8]
C  [kernel32.dll+0x202ed]

Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j  sun.awt.windows.WToolkit.eventLoop()V+0
j  sun.awt.windows.WToolkit.run()V+69
j  java.lang.Thread.run()V+11
v  ~StubRoutines::call_stub

ネイティブフレーム内のどこかにテキスト awt.dll が現れた場合、そのクラッシュは AWT に関係している可能性があります。

2.6.2 AWT のクラッシュをトラブルシューティングする方法

AWT クラッシュの大部分は Windows プラットフォーム上で発生しますが、それらの原因はスレッドの競合です。これらの問題の多くが Java SE version 6 で修正されたので、以前のリリースでクラッシュが発生した場合はまず、その問題がすでに最新リリースで修正されているか確認してみてください。

考えられるクラッシュの原因の 1 つは、AWT の多くの操作が非同期であることです。たとえば、frame.setVisible(true) を呼び出してフレームを表示させる場合、この呼び出しから戻ったあとでそのフレームがアクティブウィンドウになっている保証はありません。

もう 1 つの例は、ネイティブのファイルダイアログに関するものです。オペレーティングシステムがこれらのダイアログを初期化して表示するまで多少の時間がかかるため、setVisible(true) を呼び出してすぐにそれらを破棄してしまうと、クラッシュが発生する可能性があります。したがって、アプリケーション内にいくつかの AWT 呼び出しがあり、それらが同時に実行されたり短時間に連続して実行されたりする場合には、呼び出しの間にある程度の遅延を挿入したり、何らかの同期を追加したりすることをお勧めします。

2.7 フォーカスの問題

このセクションには次の情報が含まれます。

2.7.1 フォーカスイベントをトレースする方法

フォーカスの問題をトラブルシューティングするには、フォーカスイベントをトレースします。まず次に示すように、単純にフォーカスリスナーをツールキットに追加します。

Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener(
   public void eventDispatched(AWTEvent e) {
      System.err.println(e);
   }
), FocusEvent.FOCUS_EVENT_MASK | WindowEvent.WINDOW_FOCUS_EVENT_MASK |
   WindowEvent.WINDOW_EVENT_MASK);

ここで System.err ストリームが使用されているのは、出力のバッファリングが行われないからです。

なお、フォーカスイベントの正しい順序は次のとおりです。

フォーカスされたウィンドウ内のコンポーネント間でフォーカスが移動する場合は、FOCUS_LOST イベントと FOCUS_GAINED イベントのみが生成されるはずです。同じ所有者が所有するウィンドウ間や、所有されるウィンドウとその所有者の間でフォーカスが移動する場合は、次のイベントが生成されるはずです。

フォーカスを失うイベントやアクティブ化のイベントが先に発生するはずです。

2.7.2 ネイティブフォーカスシステムとの通信

時折、ネイティブプラットフォームが原因で問題が発生することがあります。これをチェックするには、フォーカスに関係するネイティブイベントを調査します。フォーカス対象のウィンドウがアクティブ化され、フォーカス対象のコンポーネントがネイティブフォーカスイベントを受け取ることを確認してください。

Windows プラットフォームのネイティブフォーカスイベントは、次のとおりです。

Windows プラットフォームでは「合成フォーカス」という概念が実装されています。つまり、フォーカス所有者コンポーネントはそのフォーカス可能状態をエミュレートするだけで、実際のネイティブフォーカスは「フォーカスプロキシ」コンポーネントに設定されます。このコンポーネントは、キーとインプットメソッドのネイティブメッセージを受け取り、それらをフォーカス所有者にディスパッチします。JDK7 より前は、フォーカスプロキシコンポーネントはフレーム/ダイアログ内の専用の非表示の子コンポーネントでした。JDK7 では、フレーム/ダイアログ自体がフォーカスプロキシとして機能します。現在は、所有されるウィンドウ内のコンポーネントだけでなく、すべての子コンポーネントのフォーカスプロキシとしても機能します。単純なウィンドウは、ネイティブフォーカスを受け取ることは決してなく、その所有者のフォーカスプロキシに依存します。ユーザーがこのメカニズムを意識することはありませんが、デバッグ時には考慮に入れるべきです。

Solaris OS および Linux の XToolkit では、AWT がフォーカスを自分で管理することを可能にするフォーカスモデルが使用されます。このモデルでは、ウィンドウマネージャーが直接トップレベルウィンドウに入力フォーカスを設定することはなく、代わりに WM_TAKE_FOCUS クライアントメッセージのみを送信することで、フォーカスを設定すべきであることを示します。その後、トップレベルウィンドウへのフォーカス設定が可能な場合は、その設定が AWT によって明示的に行われます。

X サーバーや一部のウィンドウマネージャーからウィンドウにフォーカスイベントが送信される可能性もあります。ただし、そのようなイベントはすべて AWT によって破棄されます。

トップレベル内のコンポーネントがフォーカスを得ても、AWT はフォーカスイベントの階層チェーンを生成しません。さらに、コンポーネント自体にマップされたネイティブウィンドウがネイティブフォーカスイベントを取得することはありません。Solaris OS および Linux プラットフォームでは Windows プラットフォームと同じく、AWT はフォーカスプロキシメカニズムを使用します。したがって、コンポーネントのフォーカスはフォーカスイベントの合成によって設定され、不可視のフォーカスプロキシがネイティブフォーカスを保持します。

Window オブジェクト (Frame オブジェクトでも Dialog オブジェクトでもない) にマップされたネイティブウィンドウには、override-redirect フラグが設定されます。したがって、ウィンドウマネージャーはそのウィンドウに対し、フォーカス移動に関して通知しません。このウィンドウでフォーカスが要求されるのは、マウスクリックへの応答としてだけです。このウィンドウはネイティブフォーカスイベントを一切受け取りません。したがって、トレース可能なイベントは、フレームまたはダイアログ上の FocusIn または FocusOut イベントだけです。XToolkit では、フォーカスの主な処理が Java レベルで発生するため、フォーカスのデバッグが WToolkit の場合よりも単純になります。

2.7.3 プラグインでのフォーカスシステム

アプレットは、EmbeddedFrame の子 (ただし直接の子ではない) としてブラウザ内に埋め込まれます。これは、プラグインとの通信機能を備えた特殊な Frame です。アプレットからは、EmbeddedFrame はトップレベルの完全な Frame に見えます。EmbeddedFrame のフォーカスを管理するには、特殊な追加アクションが必要になります。アプレットが最初に起動する際に、EmbeddedFrame はネイティブシステムによってデフォルトでアクティブ化されません。アクティブ化は、EmbeddedFrame に用意された特殊な API をプラグインがトリガーすることによって実行されます。フォーカスがアプレットを離れる際の EmbeddedFrame の非アクティブ化も、合成された方法で行われます。

2.7.4 X ウィンドウマネージャーでサポートされているフォーカスモデル

X ウィンドウマネージャーでサポートされているフォーカスモデルは、次のとおりです。

Java SE 7 の XAWT では focus-follows-mouse モードは検出されませんが、これにより、単純なウィンドウ (java.awt.Window クラスのオブジェクト) で問題が発生します。そのようなウィンドウには override-redirect プロパティーが設定されているため、ウィンドウにフォーカスを移動できるのはマウスボタンを押した場合だけであり、ウィンドウの上にマウスを移動してもフォーカスは移動しません。回避方法としては、ウィンドウに MouseListener を設定し、マウスがウィンドウのボーダーを横切ったときにウィンドウへのフォーカスを要求します。

2.7.5 その他のフォーカス問題

このセクションでは、AWT で発生する可能性のあるいくつかのフォーカス問題を説明し、その解決方法を提示します。

問題: Linux + KDE、XToolkit。フレームのタイトルをクリックしても、2 つのフレーム間でフォーカスを切り替えることができません。

フレームの内側にあるコンポーネントをクリックすると、フォーカスが変更されます。

解決方法: ウィンドウマネージャーのバージョンをチェックし、3.0 以上にアップグレードします。

問題: Tab/Shift+Tab でフォーカスを移動するために KeyListener を使ってフォーカスを管理しても、キーイベントが現れません。

解決方法: トラバーサルキーイベントをキャッチするには、Component.setFocusTraversalKeysEnabled(boolean) を呼び出してそれらのイベントを有効にする必要があります。

問題: Window.setModalExclusionType(ModalExclusionType) でウィンドウがモーダル除外に設定されます。

その所有者であるフレームはモーダルブロックされています。この場合、ウィンドウもモーダルブロックされたままになります。

解決方法: ウィンドウは、その所有者がフォーカスの取得を許可されていない場合はフォーカスされたウィンドウになれません。解決方法は、所有者をモーダリティーから除外することです。

問題: MS Windows。コンポーネントがフォーカスを要求し、同時にそのコンテナから削除されます。

java.lang.NullPointerException: null pData がスローされる場合があります。

解決方法: 例外のスローを避けるもっとも簡単な方法は、削除とフォーカス要求を EDT 上で行うことです。もう 1 つのより複雑なアプローチは、フォーカス要求と削除を同期することです (これらのアクションをそれぞれ異なるスレッド上で実行する必要がある場合)。

問題: あるコンポーネントがフォーカスを要求してすぐにフォーカス所有者が削除された場合、その削除されたコンポーネントのあとのコンポーネントにフォーカスが移動します。

たとえば、コンポーネント A がフォーカス所有者とします。コンポーネント B がフォーカスを要求し、その直後にコンポーネント A がそのコンテナから削除されます。フォーカスは最終的に、コンテナ内でコンポーネント A のあとに配置されたコンポーネント C に移動し、コンポーネント B には移動しません。

解決方法: この場合、フォーカス要求がコンポーネント A の削除前ではなく削除後に実行されるようにしてください。

問題: MS Windows。非アクティブなフレーム内のウィンドウを alwaysOnTop に設定した場合、そのウィンドウはキーイベントを受け取れません。

たとえば、フレームが 1 つと、そのフレームが所有するウィンドウが 1 つ表示されているとします。フレームがアクティブでないため、ウィンドウはフォーカスされません。その後、ウィンドウを alwaysOnTop に設定します。ウィンドウはフォーカスを取得しますが、その所有者は非アクティブなままです。したがって、ウィンドウはキーイベントを受け取れません。

解決方法: ウィンドウを alwaysOnTop に設定する前に、フレームを前面に移動します (Frame.toFront() メソッド)。

問題: SplashScreen が表示され、その SplashScreen ウィンドウが閉じたあとでフレームが表示された場合、フレームはアクティブ化されません。

解決方法: フレームを表示したあとで (Frame.setVisible(true) メソッド)、フレームを前面に移動します (Frame.toFront() メソッド)。

問題: WindowFocusListener.windowGainedFocus(WindowEvent) メソッドがフレームの直近のフォーカス所有者を返しません。

たとえば、あるフレームがフォーカスされたウィンドウであり、そのコンポーネントの 1 つがフォーカス所有者であるとします。別のウィンドウがクリックされたあと、このフレームが再度クリックされます。WINDOW_GAINED_FOCUS がフレームに送信され、WindowFocusListener.windowGainedFocus(WindowEvent) メソッドが呼び出されます。ただし、このコールバックの内部では、Frame.getMostRecentFocusOwner() から null が返されるため、フレームの直近のフォーカス所有者を確認できません。

解決方法: WindowListener.windowActivated(WindowEvent) コールバックの内部では、フレームの直近のフォーカス所有者を取得できます。ただし、この時点までにフレームがフォーカスされたウィンドウになっているのは、フレームが所有するウィンドウが 1 つも存在しない場合だけです。このアプローチは、ウィンドウでは機能せず、フレームまたはダイアログでのみ機能します。

問題: アプレットが起動時にフォーカスを横取りします。

解決方法: この動作は、JDK 1.3 以降のデフォルト動作です。ただし、アプレットが起動時にフォーカスを取得しないようにする必要がある場合もあります (アプレットが不可視であるためにフォーカスがまったく不要な場合など)。この場合は次のように、HTML タグ内で特殊パラメータ initial_focusfalse に設定できます。

<applet code="MyApplet" width=50 height=50>
<param name=initial_focus value="false">
</applet>
問題: Component.setEnabled(false) でウィンドウを無効にしても、完全にフォーカス不可能な状態にはなりません。

解決方法: Component.setEnabled(false) または Component.setFocusable(false) を呼び出すことで設定された状態が、そのすべてのコンテンツでもフォーカス不可能な状態として維持されるとは仮定しないでください。代わりに、Window.setFocusableWindowState(boolean) メソッドを使用します。

2.8 ドラッグ&ドロップ

このセクションでは、ドラッグ&ドロップやクリップボードで発生する可能性のある問題について説明します。

2.8.1 ドラッグ&ドロップアプリケーションのデバッグ

デバッガを使ってドラッグ&ドロップをトラブルシューティングすることは困難です。ドラッグ&ドロップの操作中はすべての入力が占有されるからです。したがって、ドラッグ&ドロップ中にブレークポイントを設定した場合には、X サーバーを再起動しなければいけない可能性があります。代わりにリモートデバッグを使用してみてください。

ドラッグ&ドロップに関するほとんどの問題のトラブルシューティングに使用可能な単純な方法が 2 つあります。

リモートデバッグに代わる方法として、遅延なしで出力する System.err.println() 関数があります。

2.8.2 ドラッグ&ドロップのよくある問題

このセクションでは、AWT のドラッグ&ドロップで頻繁に発生するいくつかの問題を説明し、トラブルシューティングの方法を提案します。

問題: 大量のデータをクリップボードからペーストすると、時間がかかりすぎます。

Clipboard.getContents() 関数を使ってペースト操作を行うと、アプリケーションが少しの間、ハングアップすることがあります (特にペースト対象データの提供元がリッチアプリケーションである場合)。

Clipboard.getContents() 関数は、使用可能なすべてのフレーバー (いくつかのテキストフレーバーやイメージフレーバーなど) に含まれるクリップボードデータを取得しますが、これはコストが高く、不要である可能性があります。

解決方法: Clipboard.getData() メソッドを使って特定のデータのみをクリップボードから取得します。1 つのフレーバーまたは少数のフレーバーのみのデータが必要な場合は、getContents() の代わりに次のいずれかの Clipboard メソッドを使用してください。

  • DataFlavor[] getAvailableDataFlavors()

  • boolean isDataFlavorAvailable(DataFlavorflavor)

  • Object getData(DataFlavorflavor)

問題: Java アプリケーションが Transferable.getTransferData() を使って DnD 操作を行う場合、ドラッグに長い時間がかかるように見えます。

転送データの初期化を必要な場合にのみ行えるよう、Transferable.getTransferData() 内に初期化コードが配置されました。

Transferable データの生成コストは高く、DnD 操作中に Transferable.getTransferData() が複数回呼び出されるため、速度が低下します。

解決方法: Transferable データが一度だけ生成されるように、このデータをキャッシュします。

問題: Java アプリケーションと GNOME/KDE デスクトップやファイルブラウザとの間でファイルを転送できません。

Windows や一部のウィンドウマネージャーでは、転送ファイルのリストは DataFlavor.javaFileListFlavor データフレーバーとして表現できます。しかし、すべてのウィンドウマネージャーがファイルのリストをこの形式で表現するわけではありません。たとえば、GNOME ウィンドウマネージャーは、ファイルリストを URI のリストとして表現します。

回避方法: ファイルを取得するには、String 型のデータを要求したあと、RFC 2483 で説明されている text/uri-list 形式に従って文字列をファイルのリストに変換します。Java アプリケーションから GNOME/KDE デスクトップやファイルブラウザにファイルをドロップできるようにするには、text/uri-list 形式でデータをエクスポートします。コード例については、次のバグレポートの Work Around のセクションを参照してください。

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4899516

問題: DragGestureEvent または DragSourcestartDrag() メソッドの 1 つに渡したイメージが、後続の DnD 操作時に表示されません。

解決方法: DnD 操作中のマウスカーソルの動きに合わせて、表面にイメージがレンダリングされたウィンドウを移動します。次の RFE の Work Around のセクションのコード例を参照してください。

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4874070

問題: ドラッグ&ドロップを使って配列を移動する方法がありません。

DataFlavor クラスには、配列を処理するコンストラクタはありません。配列の MIME タイプには、エスケープすべき文字が含まれます。たとえば、次のコードでは IllegalArgumentException がスローされます。

new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType + 
"; class=" + 
(new String[0]).getClass().getName())

解決方法: 次のコードに示すように、表現クラスのパラメータの値を引用符で囲みます (引用符がエスケープされている)。

new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType + 
"; class=" + 
"\"" + 
(new String[0]).getClass().getName() + 
"\"")

詳細については、次のバグレポートを参照してください。

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4276926

問題: Swing コンポーネントで AWT のドラッグ&ドロップサポートを使用すると、問題が発生します。

DnD 操作時に奇妙なイベントが発生する、複数の項目をドラッグ&ドロップできない、InvalidDnDOperationException がスローされるなど、さまざまな問題が発生する可能性があります。

解決方法: Swing コンポーネントでは Swing の DnD サポートを使用します。Swing の DnD 実装は AWT の DnD 実装に基づいていますが、Swing と AWT のドラッグ&ドロップを混在させることはできません。次のドキュメントを参照してください。

問題: ターゲットに依存するようにソースの状態を変更する方法がありません。

ターゲットに依存するようにソースの状態を変更するには、ソースコンポーネントとターゲットコンポーネントへの参照が同じコード領域内で必要になりますが、これは現時点ではドラッグ&ドロップ API に実装されていません。

回避方法: 回避方法の 1 つは、イベントのコンテキストを判定できるようにするためのフラグを、転送可能オブジェクトに追加することです。

1 つの Java VM 内でのデータ転送では、次の回避方法を提案します。

  • ターゲットコンポーネントを DragSourceListener として実装します。

  • DragGestureRecognizer.dragGestureRecognized() 内で次のように、ターゲットをドラッグソースリスナーとして追加します。

    public void dragGestureRecognized(DragGestureEvent dge) {
                 dge.startDrag(null, new StringSelection("SomeTransferedText"));
                 dge.getDragSource().addDragSourceListener(target);             
            }
    
  • これで、DragSourceListener()dragEnter()dragOver()dropActionChanged()dragDropEnd() の各メソッド内で、ターゲットとソースを取得できます。

問題: アプリケーション内でのオブジェクト転送に長い時間がかかります。

大量データの転送や転送オブジェクトの作成にかかる時間が長すぎます。ユーザーは、データ転送が完了するまで長時間待つ必要があります。

この高コスト処理で転送に時間がかかりすぎるのは、Transferable.getTransferData() が終了するまで待つ必要があるからです。

解決方法: この解決方法が有効なのは、1 つの Java VM 内でデータを転送する場合だけです。ドラッグ操作の前に、高コストのリソースを作成または取得しておきます。たとえば、Transferable.getTransferData() の処理時間が長くなりすぎないよう、転送可能オブジェクトの作成時にファイルのコンテンツを取得します。

2.9 その他の問題

このセクションでは、AWT のトラブルシューティングに関するその他の問題について説明します。

2.9.1 スプラッシュ画面の問題

このセクションでは、Java SE 7 リリースの AWT のスプラッシュ画面で発生する可能性のあるいくつかの問題を説明し、その解決方法を提示します。

問題: 適切な MANIFEST.MF を含む JAR ファイルを -classpath に指定しても、スプラッシュ画面が機能しません。

解決方法: 次の解決方法を参照してください。

問題: アプリケーションのいくつかの JAR ファイルのどれにスプラッシュ画面のイメージを含めるべきかが、明らかではありません。

解決方法: スプラッシュ画面のイメージが JAR ファイルから選択されるのは、-jar コマンド行オプションで JAR ファイルが使用された場合だけです。この JAR ファイルには、「SplashScreen-Image」マニフェストオプションとイメージファイルの両方を含めるべきです。-classpath の JAR ファイルの MANIFEST.MF 内でスプラッシュ画面がチェックされることは決してありません。-jar を使用しない場合でも、コマンド行で -splash を使ってスプラッシュ画面のイメージを指定できます。

問題: Solaris OS および Linux 上で半透明の PNG のスプラッシュ画面が機能しません。

解決方法: これは、X11 のネイティブの制限です。Solaris OS および Linux では、半透明イメージのアルファチャネルが 50% のしきい値と比較されます。アルファ値が 0.5 より高いピクセルは不透明に、アルファが 0.5 より低いピクセルは完全に透明になります。半透明のサポートは、Java SE の将来のバージョンで改善される可能性があります。

2.9.2 トレイアイコンの問題

Windows 98 プラットフォームの Java SE 6 リリースではメソッド TrayIcon.displayMessage() はサポートされませんが、これは、Windows 98 ではバルーン表示用のネイティブサービスがサポートされていないからです。

SecurityManager がインストールされている場合、TrayIcon オブジェクトを作成するには、AWTPermission の値が accessSystemTray に設定される必要があります。

2.9.3 ポップアップメニューの問題

JPopupMenu.setInvoker() メソッドで、呼び出し元 (invoker) とは、ポップアップメニューの表示先となるコンポーネントのことです。このプロパティーが null に設定されていると、ポップアップメニューが正しく機能しません。

解決方法は、ポップアップの呼び出し元を自分自身に設定することです。

2.9.4 バックグラウンド/フォアグラウンドカラーの継承

多くの AWT コンポーネントでは、バックグラウンドカラーやフォアグラウンドカラーとして、親のカラーではなく独自のデフォルトが使用されます。

この動作はプラットフォームに依存します。同じコンポーネントの動作がプラットフォームごとに異なる可能性があります。さらに一部のコンポーネントでは、バックグラウンドカラーまたはフォアグラウンドカラーの一方でデフォルト値が使用され、他方で親の値が選択されます。

アプリケーションの一貫性をすべてのプラットフォームで確保するには、すべてのコンポーネントやコンテナで、明示的なカラー割り当て (フォアグラウンドとバックグラウンドの両方) を使用してください。

2.9.5 AWT パネルのサイズ制限

AWT の Container にはサイズの制限があります。ほとんどのプラットフォームでは、この制限は 32767 ピクセルです。したがって、たとえばキャンバスオブジェクトの高さが 25 ピクセルであれば、Java AWT パネル上に約 1400 個を超える数のオブジェクトを表示することはできません。

残念ながら、Java コードやネイティブコードを使ってこの制限を変更する方法はありません。この制限は、オペレーティングシステムでウィジェットサイズの格納に使用されるデータの型に依存します。たとえば、Windows 2000/XP オペレーティングシステムや Linux オペレーティングシステムでは integer 型が使用されるため、整数の最大サイズが制限値となります。ほかのオペレーティングシステムでは、long など別の型が使用されている可能性があり、この場合であれば制限は高くなります。

詳細については、プラットフォームのドキュメントを参照してください。

役立つ可能性のあるこの制限の回避方法の例を次に示します。

2.9.6 X11 上でポップアップメニューや類似コンポーネントをデバッグする際にハングアップする

特定の GUI アクション (ポップアップメニューのナビゲーションなど) では、アクションの終了タイミングを判定できるようにすべての入力イベントを占有する必要があります。占有が続いている間は、ほかのアプリケーションは入力イベントを一切受け取りません。Java アプリケーションのデバッグ時に、占有が継続している間にブレークポイントに達すると、オペレーティングシステムがハングアップしたようになります。これは、占有を保持している Java アプリケーションがデバッガによって停止され、入力イベントを一切処理できくなったからであり、このインストールされた占有のために、ほかのアプリケーションは単純にイベントを受け取りません。そのようなアプリケーションのデバッグを可能にするには、デバッガからアプリケーションを実行する際に次のシステムプロパティーを設定するようにしてください。

-Dsun.awt.disablegrab=true

これにより事実上、占有の設定がオフになるので、システムがハングアップしなくなります。ただし、このオプションが設定されていると、場合によっては、通常であれば終了するはずの GUI アクションが終了できなくなります。たとえば、ウィンドウのタイトルバーをクリックしてもポップアップメニューが終了しない可能性があります。

2.9.7 X11 での Window.toFront()/toBack() の動作

サードパーティーソフトウェア (特に Metacity などのウィンドウマネージャー) から課される制限のため、toFront()/toBack() メソッドは必ずしも予想どおりに機能せず、ほかのトップレベルウィンドウとの関係におけるウィンドウのスタック順序が変更されない可能性があります。詳細については、CR 6472274 を参照してください。

アプリケーションがあるウィンドウを最終的に最前面に移動させたい場合、この問題を回避するために、Window.setAlwaysOnTop(true) を呼び出してそのウィンドウを一時的に「常時最前面」にしたあと、setAlwaysOnTop(false) を呼び出して「常時最前面」状態をリセットすることができます。この回避方法も成功が保証されているわけではありません。将来ウィンドウマネージャーによってより多くの制限が課される可能性もあるからです。さらに、ウィンドウを「常時最前面」に設定できるのは、信頼できるアプリケーションだけです。サンドボックス内で実行される未署名のアプレットや Web Start アプリケーションは、この API を使用できず、したがって問題を回避できません。

ただし、ネイティブアプリケーションも似た問題に悩まされているので、この特殊性により、Java アプリケーションの動作はネイティブアプリケーションと似たものになっています。したがって、この問題はバグとはみなせません。

2.10 重量/軽量コンポーネントの混在

このセクションでは、重量/軽量 (HW/LW) 混在機能で発生する可能性のある問題について説明します。

2.10.1 コンポーネント階層の有効化の要件

コンポーネントのレイアウト関係のプロパティー (サイズ、位置、フォントなど) を 1 つでも変更すると、コンポーネントとその祖先が無効にされます。HW/LW 混在機能が正しく機能するには、そのような変更を行なったあとでコンポーネント階層を有効にする必要があります。無効化はデフォルトで、階層内の最上位コンテナ (Frame オブジェクトなど) で停止します。したがって、階層の有効性を復元するには、アプリケーションから Frame.validate() メソッドを呼び出すようにしてください。例:

component.setFont(myFont);
frame.validate();

ここで、framecomponent を含んでいるフレームのことです。Swing アプリケーションや Swing ライブラリ自身では、よく次のパターンが使用されます。

component.setFont(myFont);
component.revalidate();

revalidate() 呼び出しは十分ではありません。階層内でコンポーネントのもっとも近い有効なルートからしか有効化が行われず、したがってそれより上のコンテナは無効なままになるからです。その場合、HW/LW 機能によって計算される重量コンポーネントの形状が正しくない可能性があり、画面上に視覚的なアーティファクトが表示される可能性があります。

コンポーネント階層全体の有効性を検証するために、ユーザーは、このドキュメントの 2.1 で説明されているキーの組み合わせ Ctrl+Shift+F1 を使用できます。コンポーネントに「invalid」というマークが付いている場合、validate() 呼び出しがどこかで欠落していることを示している可能性があります。

2.10.2 有効なルート

2.10.1 で言及した有効なルートの概念は Swing で導入されたものですが、その目的は、非常に長い時間がかかる可能性のあるコンポーネント階層の有効化処理を高速化するためでした。そのような最適化を行うと階層の上側の部分は無効なままになりますが、問題はありません。有効なルートの内側にあるコンポーネントのレイアウトは、外側のコンポーネント階層 (つまり有効なルートの兄弟) のレイアウトには影響しないからです。ただし、HW コンポーネントと LW コンポーネントが階層内で一緒に混在している場合、この文は正しくありません。それが、この機能でコンポーネント階層全体が有効でなければいけない理由です。

frame.validate() の呼び出しも効率的ではない可能性があるため、AWT では、コンポーネント階層の無効化/有効化を処理するための最適化された代替手段がサポートされています。この機能を有効にするには、システムプロパティーを使用します。

-Djava.awt.smartInvalidate=true

このプロパティーが指定されると、invalidate() メソッドは、invalidate() メソッドを呼び出したコンポーネントのもっとも近い有効なルートに達した時点で、階層の無効化を停止するようになります。その後、アプリケーションは次を単純に呼び出すようにしてください。

component.revalidate();

これで、コンポーネント階層の有効性が復元されます。この場合、フレームはまだ有効であるため、frame.validate() の呼び出しは事実上無操作になります。一部のアプリケーションは、階層の有効なルート (フレームなど) より上側にあるコンポーネントで直接 validate() を呼び出すことに依存しているため、この新しい最適化された動作によって非互換性の問題が発生する可能性があり、したがってこの動作を使用できるのはシステムプロパティーを指定した場合だけです。

この最適化された新しいモードでアプリケーションを実行する際に何らかの問題が発生する場合、ユーザーは、このドキュメントの 2.1 で説明したキーの組み合わせ Ctrl+Shift+F1 を使用することで、コンポーネント階層のどの部分が無効なままになっており、したがって問題の原因となっている可能性があるのかを調査できます。

2.10.3 Swing のペイントの最適化

デフォルトでは、Swing ライブラリはコンポーネント階層内に重量コンポーネントは 1 つも存在しないものと仮定しているため、最適化された描画テクニックを使って Swing UI のパフォーマンスを向上させます。コンポーネント階層に HW コンポーネントが含まれている場合は、最適化をオフにする必要があります。これにはまず Swing の JScrollPane が該当します。スクロールモードを変更するには、JViewPort.setScrollMode(int) メソッドを使用します。

2.10.4 不透明でない軽量コンポーネント

HW/LW 混在機能実装ではデフォルトで、不透明でない軽量コンポーネントはサポートされません。矩形以外の LW コンポーネントを HW コンポーネントと混在できるようにするには、アプリケーションで非公開 API の com.sun.awt.AWTUtilities.setComponentMixingCutoutShape() を使用する必要があります。

ただし、矩形でない LW コンポーネントは、引き続き不透明 (アルファ == 1.0) または透明 (アルファ == 0.0) のいずれかのカラーを使用して自身をペイントするようにしてください。半透明カラー (0.0 < アルファ < 1.0) の使用はサポートされません。

2.10.5 デフォルトの HW/LW 混在機能実装の無効化

一部の開発者は以前、HW および LW コンポーネントを一緒に混在させなければいけない場合のために、独自のサポートを実装しました。JDK 6 Update 12 および JDK 7 以降で使用可能な機能の組み込み実装が、カスタムの回避方法との間で問題を発生させる可能性があります。この組み込み機能を無効にするには、アプリケーションの起動時に次のシステムプロパティーを指定する必要があります。

-Dsun.awt.disableMixing=true