11 AWT
この章の構成は、次のとおりです。
AWTのデバッグに関するヒント
この項では、AWTに関する問題のデバッグに役立つヒントについて説明します。
AWTコンポーネント階層をダンプするには、[Ctrl]+[Shift]+[F1]を押します。
アプリケーションがハングアップした場合、Windowsでは[Ctrl]+[Break]を押し(SIGBREAKシグナルが送信される)、Linuxオペレーティング・システムでは[Ctrl]+[\]を押します(SIGQUITシグナルが送信される)。
Linuxオペレーティング・システムでX11エラーをトレースするには、sun.awt.noisyerrorhandler
システム・プロパティをtrue
に設定します。
AWTの問題をデバッグする際には、ロガーによって生成される出力が役立ちます。詳細は、パッケージjava.util.logging
の説明を参照してください。
使用可能なロガーは次のとおりです。
java.awt
java.awt.focus
java.awt.event
java.awt.mixing
sun.awt
sun.awt.windows
sun.awt.X11
レイアウト・マネージャの問題
この項では、レイアウト・マネージャに関連して発生する可能性のある問題について説明し、回避方法がある場合はその方法を提供します。
キー・イベント
キー・イベントの処理に関するいくつかの問題は、現在のリリースでは解決策がありません。
現在解決されていないキーボードの問題は、次のとおりです。
-
一部の非英語キーボードでは特定のアクセント・キーがキーに刻印されているため、それらはプライマリ・レイヤーの文字になります。ところが、それらに対応するJavaキー・コードがないため、ニーモニックとして使用できません。
-
実行時にデフォルトのロケールを変更しても、メニューのアクセラレータ・キーとして表示されるテキストが変更されません。
-
標準109キー日本語キーボードでは、円記号キーとバックスラッシュ・キーのどちらの場合もバックスラッシュが生成されますが、これは両者の
WM_CHAR
メッセージの文字コードが同じであるためです。AWTはそれらを区別すべきです。
モーダリティの問題
この項では、モーダリティの使用に関連する問題について説明します。
この項では、次の問題について説明します。
-
UNIXのウィンドウ・マネージャ:
一部のLinux環境(共通デスクトップ環境(CDE)のウィンドウ・マネージャを使用する場合など)では、モーダリティの改善点の多くは使用できません。あるモーダリティ・タイプやモーダル除外タイプが特定の構成でサポートされているかどうかを確認するには、次のメソッドを使用します:
-
Toolkit.isModalityTypeSupported()
-
Toolkit.isModalExclusionTypeSupported()
モーダル・ダイアログ・ボックスが画面に表示されると、ウィンドウ・マネージャは同じアプリケーション内の一部のJavaトップレベル・ウィンドウがタスクバーに表示されないようにすることがあります。これはエンド・ユーザーを困惑させることがありますが、非表示になっているウィンドウはすべてモーダル・ブロックされていて操作できないため、ユーザーの作業に大きな影響はありません。
-
-
モーダリティのその他の問題:
モーダリティ関連の機能とその使用方法の詳細は、AWTのモーダリティの仕様に関する項を参照してください。
その仕様の項の1つでは、モーダル・ダイアログ・ボックスに関係したりその影響を受けたりする可能性のあるAWT機能(常時最前面プロパティ、フォーカス処理、ウィンドウ状態など)をいくつか説明しています。そのような場合のアプリケーションの動作は通常、未定義となるかプラットフォームに依存するので、特定の動作をあてにしないでください。
フォーカス・イベント
次の項では、フォーカス・イベントに関連する問題のトラブルシューティングについて説明します。
フォーカス・イベントをトレースする方法
次の例に示すように、フォーカス・リスナーをツールキットに追加して、フォーカス・イベントをトレースできます。
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
-
フォーカスを失うトップ・レベルの
WINDOW_LOST_FOCUS
-
アクティブ状態を失うトップ・レベルの
WINDOW_DEACTIVATED
-
アクティブ・ウィンドウになるトップ・レベルの
WINDOW_ACTIVATED
-
フォーカスされたウィンドウになるトップ・レベルの
WINDOW_GAINED_FOCUS
-
フォーカスを得るコンポーネントの
FOCUS_GAINED
フォーカスされたウィンドウ内のコンポーネント間でフォーカスが移動する場合は、FOCUS_LOST
イベントとFOCUS_GAINED
イベントのみが生成されるはずです。同じ所有者が所有するウィンドウ間や、所有されるウィンドウとその所有者の間でフォーカスが移動する場合は、次のイベントが生成されるはずです。
-
FOCUS_LOST
-
WINDOW_LOST_FOCUS
-
WINDOW_GAINED_FOCUS
-
FOCUS_GAINED
ノート:
フォーカスまたはアクティベーションを失うイベントが最初に来る必要があります。ネイティブ・フォーカス・システム
時折、ネイティブ・プラット・フォームが原因で問題が発生することがあります。これをチェックするには、フォーカスに関係するネイティブ・イベントを調査します。
フォーカス対象のウィンドウがアクティブ化され、フォーカス対象のコンポーネントがネイティブ・フォーカス・イベントを受け取ることを確認してください。
Windowsプラットフォームのネイティブ・フォーカス・イベントは、次のとおりです。
-
WM_ACTIVATE
(トップ・レベル用)。WPARAM
は、アクティブ化の際はWA_ACTIVE
、非アクティブ化の際はWA_INACTIVE
になります。 -
WM_SETFOCUS
およびWM_KILLFOCUS
(コンポーネント用)。
Windowsプラットフォームでは、合成フォーカス という概念が実装されています。つまり、フォーカス所有者コンポーネントはそのフォーカス可能状態をエミュレートするだけですが、実際のネイティブ・フォーカスはフォーカス・プロキシ・コンポーネントに設定されます。このコンポーネントは、キーとインプット・メソッドのネイティブ・メッセージを受け取り、それらをフォーカス所有者にディスパッチします。最新のJDKリリースでは、フレームまたはダイアログ・ボックスがフォーカス・プロキシとして機能します。現在は、所有されるウィンドウ内のコンポーネントだけでなく、すべての子コンポーネントのフォーカス・プロキシとしても機能します。単純なウィンドウは、ネイティブ・フォーカスを受け取ることは決してなく、その所有者のフォーカス・プロキシに依存します。ユーザーがこのメカニズムを意識することはありませんが、デバッグ時には考慮に入れるべきです。
Linuxオペレーティング・システム上のXToolkitでは、AWT自体がフォーカスを管理できるフォーカス・モデルを使用しています。このモデルでは、ウィンドウ・マネージャが直接トップレベル・ウィンドウに入力フォーカスを設定することはなく、代わりにWM_TAKE_FOCUS
クライアント・メッセージのみを送信することで、フォーカスを設定すべきであることを示します。その後、トップレベル・ウィンドウへのフォーカス設定が可能な場合は、その設定がAWTによって明示的に行われます。
ノート:
Xサーバーおよび一部のウィンドウ・マネージャは、ウィンドウにフォーカス・イベントを送信することがあります。ただし、これらのイベントはAWTによって破棄されます。トップ・レベル内のコンポーネントがフォーカスを得ても、AWTはフォーカス・イベントの階層チェーンを生成しません。さらに、コンポーネントにマップされたネイティブ・ウィンドウはネイティブ・フォーカス・イベントを取得しません。LinuxプラットフォームではWindowsプラットフォームと同じく、AWTはフォーカス・プロキシ・メカニズムを使用します。したがって、コンポーネントのフォーカスはフォーカス・イベントの合成によって設定され、不可視のフォーカス・プロキシがネイティブ・フォーカスを保持します。
Window
オブジェクト(Frame
オブジェクトでもDialog
オブジェクトでもない)にマップされたネイティブ・ウィンドウには、override-redirect
フラグが設定されます。したがって、ウィンドウ・マネージャはそのウィンドウに対し、フォーカス移動に関して通知しません。このウィンドウでフォーカスが要求されるのは、マウス・クリックへの応答としてだけです。このウィンドウはネイティブ・フォーカス・イベントを一切受け取りません。したがって、トレース可能なイベントは、フレームまたはダイアログ・ボックス上のFocusIn
またはFocusOut
イベントだけです。XToolkitでは、フォーカスの主な処理がJavaレベルで発生するため、フォーカスのデバッグがWToolkitの場合よりも単純になります。
Xウィンドウ・マネージャでサポートされているフォーカス・モデル
Xウィンドウ・マネージャでサポートされているフォーカス・モデルは、次のとおりです。
-
Click-to-focusは一般的に使用されているフォーカス・モデルです。(たとえば、Microsoft Windowsではこのモデルが使用されています。)
-
Focus-follows-mouseは、マウスの下にあるウィンドウにフォーカスが移動するフォーカス・モデルです。
データ転送
次の項では、ドラッグ・アンド・ドロップ(DnD)およびカット・アンド・ペースト/コピー・アンド・ペースト(CCP)操作をアプリケーションに追加できるようにする、データ転送機能に関連して発生する可能性のある問題について説明します。
ドラッグ・アンド・ドロップ・アプリケーションのデバッグ
デバッガを使用してDnD機能をトラブルシューティングするのは困難です。ドラッグ・アンド・ドロップ操作中はすべての入力がグラブされるからです。そのため、DnDの操作中にブレークポイントを入れた場合は、Xサーバーの再起動が必要になることがあります。かわりに、リモート・デバッグを使用してみてください。
DnDに関するほとんどの問題のトラブルシューティングには、2つの単純な方法を使用できます。
その他の問題
次の各項では、他の問題をトラブルシューティングするためのヒントについて説明します。
トレイ・アイコンの問題
SecurityManager
がインストールされている場合、TrayIcon
オブジェクトを作成するには、AWTPermission
の値がaccessSystemTray
に設定される必要があります。
ポップアップ・メニューの問題
JPopupMenu.setInvoker()メソッドで、呼出し元(invoker)とは、ポップアップ・メニューの表示先となるコンポーネントのことです。このプロパティがnull
に設定されていると、ポップアップ・メニューが正しく機能しません。
解決方法は、ポップアップ・メニューの呼出し元を自分自身に設定することです。
背景色または前景色の継承
アプリケーションの一貫性をすべてのプラットフォームで確保するには、すべてのコンポーネントやコンテナで、明示的なカラー割り当て(背景と前景の両方)を使用してください。
多くのAWTコンポーネントでは、背景色や前景色として、親の色ではなく独自のデフォルトが使用されます。
この動作はプラットフォームに依存しています。つまり、プラットフォームが異なれば、同じコンポーネントでも違った動作になることがあります。また、コンポーネントの中には背景色または前景色のどちらか一方にはデフォルト値を使用するが、もう一方の色については親の値を取るものもあります。
AWTパネルのサイズ制限
AWTのコンテナにはサイズの制限があります。ほとんどのプラットフォームでは、この制限は32,767ピクセルです。
したがって、たとえばキャンバス・オブジェクトの高さが25ピクセルであれば、Java AWTパネル上に1310個を超える数のオブジェクトを表示することはできません。
残念ながら、この制限を変更する方法はなく、Javaコードやネイティブ・コードを使用しても変更できません。この制限は、オペレーティング・システムでウィジェット・サイズの格納に使用されるデータの型に依存します。たとえば、Linux X Windowsシステムでは、 integer
型が使用されるため、整数の最大サイズが制限値となります。他のオペレーティング・システムでは、long
など別の型が使用されている可能性があり、この場合であれば制限は高くなります。
ご使用のプラットフォームのドキュメントを参照してください。
役立つ可能性のあるこの制限の回避方法の例を次に示します。
- コンポーネントをページ単位で表示します。
- タブを使って一度に表示されるコンポーネントの数を減らします。
X11上でポップアップ・メニューや類似コンポーネントのデバッグ中にハングアップする
特定のグラフィカル・ユーザー・インターフェイス(GUI)コンポーネントのデバッグ時に-Dsun.awt.disablegrab=true
システム・プロパティを設定します。
特定のグラフィカル・ユーザー・インタフェース(GUI)のアクションでは、そのアクションを終了させるタイミングを決めるために、すべての入力イベントをグラブする必要があります(ポップアップ・メニューの移動など)。占有が続いている間は、ほかのアプリケーションは入力イベントを一切受け取りません。Javaアプリケーションのデバッグ時に、グラブがアクティブの間にブレークポイントに達すると、オペレーティング・システムがハングアップしたようになります。これは、グラブを保持しているJavaアプリケーションがデバッガによって停止され、入力イベントを一切処理できなくなったために起こります。他のアプリケーションは、このインストールされたグラブが原因でイベントを受け取りません。そのようなアプリケーションのデバッグを可能にするには、デバッガからアプリケーションを実行する際に次のシステム・プロパティを設定するようにしてください。
-Dsun.awt.disablegrab=true
このプロパティにより事実上、グラブの設定がオフになるので、システムがハングアップしなくなります。ただし、このオプションが設定されていると、場合によっては、通常であれば終了するはずのGUIアクションが終了できなくなります。たとえば、ウィンドウのタイトル・バーをクリックしてもポップアップ・メニューが終了しない可能性があります。
X11でのWindow.toFront()/toBack()の動作
サードパーティ・ソフトウェア(特にMetacityなどのウィンドウ・マネージャ)から課される制限のため、toFront()/toBack()メソッドが予想どおりに機能せず、他のトップレベル・ウィンドウとの関係におけるウィンドウのスタック順序が変更されない可能性があります。
詳細については、CR 6472274を参照してください。
アプリケーションでウィンドウが手前に表示されるようにする場合は、まずWindow.setAlwaysOnTop(true)を呼び出して一時的にウィンドウが常に手前に表示されるようにしてから、setAlwaysOnTop(false)を呼び出して「常に手前に表示」の状態をリセットすることで、この問題の回避を試みることができます。
ノート:
ウィンドウ・マネージャから課される制約が強化される可能性があるため、この回避方法の動作は保証されません。また、ウィンドウを「常に手前に表示」に設定できるのは信頼できるアプリケーションのみです。
ただし、ネイティブ・アプリケーションも似た問題に悩まされているので、この特殊性により、Javaアプリケーションの動作はネイティブ・アプリケーションと似たものになっています。