この章には、次のセクションがあります。
AWTに関する問題のデバッグに役立つヒント。
AWTコンポーネント階層をダンプするには、[Ctrl]+[Shift]+[F1]を押します。
アプリケーションがハングアップした場合、Windowsでは[Ctrl]+[Break]を押し(SIGBREAKシグナルが送信される)、Oracle SolarisおよびLinuxオペレーティング・システムでは[Ctrl]+[\]を押します(SIGQUITシグナルが送信される)。
Oracle SolarisおよびLinuxオペレーティング・システムでX11エラーをトレースするには、sun.awt.noisyerrorhandler
システム・プロパティをtrue
に設定します。Java SE 6以前のリリースでは、NOISY_AWT
環境変数がこの目的で使用されていました。
Java SE 8より前は、AWTのイベント・ディスパッチ・スレッド(EDT)でスローされた例外をキャッチするには、システム・プロパティsun.awt.exception.handler
にpublic void handle(Throwable)
メソッドを実装するクラスの名前を設定していました。Java SE 8ではこのメカニズムが更新され、標準のThread.UncaughtExceptionHandler
インタフェースが使用されるようになりました。
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はそれらを区別すべきです。
Oracle Solaris 10およびLinux x86システムに関係するキーボードの問題を次に示します。
これらのシステムでのキーボード入力は通常、X Window SystemのXキーボード拡張(XKB)に基づいています。ユーザーは、1つのキーボード・レイアウト(例: デンマーク語のdk
)のみを構成することも、いくつかのレイアウト(例: us
とdk
)を構成して切り替えることもできます。
sk
、hu
、cz
などの一部のキーボード・レイアウトでは、数値入力キーパッドの小数点を押したときに、小数点の入力だけでなく1つ前の文字の削除も行われます。その原因はネイティブのバグにあります。回避方法は、us
とsk
など、2つのレイアウトを使用することです。この場合、どちらのレイアウトでも数値入力キーパッドは正しく動作します。
キーボードの動的変更をサポートするUNIXシステム上で、実行中のJavaアプリケーションはそのような変更を認識しません。たとえば、キーボードをUSからドイツ語に変更しても、キーボード・マッピングは変更されません。Xサーバーはその変更を検出して対象クライアントにMappingNotify
イベントを送出しますが、AWTはキー・コード - キーシム・マッピングの情報をリフレッシュしません。
モーダリティの使用に関連する問題についての情報
Java SE 6リリースでは、AWTモーダリティの領域で多くの問題が解決され、多くの改善が実装されました。Java SE 1.5以前のリリースでモーダリティの問題が発生している場合は、まず最新のJava SEリリースにアップグレードし、問題がすでに修正されているか確認してください。
Java SE 6で修正された問題のいくつかを次に示します。
ブロックされたフレームの背後にモーダル・ダイアログ・ボックスが移動します。
同じウィンドウを親に持つ2つのモーダル・ダイアログ・ボックスが同時に開いていました。
この項では、次の問題について説明します。
UNIXのウィンドウ・マネージャ:
一部のOracle SolarisまたはLinux環境(共通デスクトップ環境(CDE)のウィンドウ・マネージャを使用する場合など)では、モーダリティの改善点の多くは使用できません。Java SE 6以降のリリースで、あるモーダリティ・タイプやモーダル除外タイプが特定の構成でサポートされているかどうかを確認するには、次のメソッドを使用します。
Toolkit.isModalityTypeSupported()
Toolkit.isModalExclusionTypeSupported()
モーダル・ダイアログ・ボックスが画面に表示されると、ウィンドウ・マネージャは同じアプリケーション内の一部のJavaトップレベル・ウィンドウがタスクバーに表示されないようにすることがあります。これはエンド・ユーザーを困惑させることがありますが、非表示になっているウィンドウはすべてモーダル・ブロックされていて操作できないため、ユーザーの作業に大きな影響はありません。
アプレット:
アプリケーションをブラウザ内のアプレットとして実行してモーダル・ダイアログ・ボックスを表示した場合、ブラウザのウィンドウがブロックされる可能性があります。このブロック処理の実装は、ブラウザやオペレーティング・システムごとに異なります。たとえば、WindowsではInternet ExplorerとMozilla Firefoxはどちらも正しく動作しますが、Oracle SolarisやLinuxオペレーティング・システムではMozilla Firefoxのウィンドウはブロックされません。
モーダリティのその他の問題:
モーダリティ関連の機能とその使用方法の詳細は、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プラットフォームでは、合成フォーカスという概念が実装されています。つまり、フォーカス所有者コンポーネントはそのフォーカス可能状態をエミュレートするだけですが、実際のネイティブ・フォーカスはフォーカス・プロキシ・コンポーネントに設定されます。このコンポーネントは、キーとインプット・メソッドのネイティブ・メッセージを受け取り、それらをフォーカス所有者にディスパッチします。JDK7より前は、フォーカス・プロキシ・コンポーネントはフレームまたはダイアログ・ボックス内の専用の非表示の子コンポーネントでした。最新のJDKリリースでは、フレームまたはダイアログ・ボックスがフォーカス・プロキシとして機能します。現在は、所有されるウィンドウ内のコンポーネントだけでなく、すべての子コンポーネントのフォーカス・プロキシとしても機能します。単純なウィンドウは、ネイティブ・フォーカスを受け取ることは決してなく、その所有者のフォーカス・プロキシに依存します。ユーザーがこのメカニズムを意識することはありませんが、デバッグ時には考慮に入れるべきです。
Oracle SolarisおよびLinuxオペレーティング・システム上のXToolkitでは、AWT自体がフォーカスを管理できるフォーカス・モデルを使用しています。このモデルでは、ウィンドウ・マネージャが直接トップレベル・ウィンドウに入力フォーカスを設定することはなく、代わりにWM_TAKE_FOCUS
クライアント・メッセージのみを送信することで、フォーカスを設定すべきであることを示します。その後、トップレベル・ウィンドウへのフォーカス設定が可能な場合は、その設定がAWTによって明示的に行われます。
注意:
Xサーバーおよび一部のウィンドウ・マネージャは、ウィンドウにフォーカス・イベントを送信することがあります。ただし、これらのイベントはAWTによって破棄されます。トップ・レベル内のコンポーネントがフォーカスを得ても、AWTはフォーカス・イベントの階層チェーンを生成しません。さらに、コンポーネントにマップされたネイティブ・ウィンドウはネイティブ・フォーカス・イベントを取得しません。Oracle SolarisおよびLinuxプラットフォームではWindowsプラットフォームと同じく、AWTはフォーカス・プロキシ・メカニズムを使用します。したがって、コンポーネントのフォーカスはフォーカス・イベントの合成によって設定され、不可視のフォーカス・プロキシがネイティブ・フォーカスを保持します。
Window
オブジェクト(Frame
オブジェクトでもDialog
オブジェクトでもない)にマップされたネイティブ・ウィンドウには、override-redirect
フラグが設定されます。したがって、ウィンドウ・マネージャはそのウィンドウに対し、フォーカス移動に関して通知しません。このウィンドウでフォーカスが要求されるのは、マウス・クリックへの応答としてだけです。このウィンドウはネイティブ・フォーカス・イベントを一切受け取りません。したがって、トレース可能なイベントは、フレームまたはダイアログ・ボックス上のFocusIn
またはFocusOut
イベントだけです。XToolkitでは、フォーカスの主な処理がJavaレベルで発生するため、フォーカスのデバッグがWToolkitの場合よりも単純になります。
アプレットは、EmbeddedFrame
の子(ただし直接の子ではない)としてブラウザ内に埋め込まれます。
これは、プラグインとの通信機能を備えた特殊なFrame
です。アプレットからは、EmbeddedFrame
はトップ・レベルの完全なFrame
に見えます。
EmbeddedFrame
のフォーカスを管理するには、特殊なアクションが必要になります。アプレットが最初に起動する際に、EmbeddedFrame
はネイティブ・システムによってデフォルトでアクティブ化されません。アクティブ化は、EmbeddedFrame
に用意された特殊なAPIをプラグインがトリガーすることによって実行されます。フォーカスがアプレットを離れる際のEmbeddedFrame
の非アクティブ化も、合成された方法で行われます。
Xウィンドウ・マネージャでサポートされているフォーカス・モデルのリスト。
Xウィンドウ・マネージャでサポートされているフォーカス・モデルは、次のとおりです。
Click-to-focusは一般的に使用されているフォーカス・モデルです。(たとえば、Microsoft Windowsではこのモデルが使用されています。)
Focus-follows-mouseは、マウスの下にあるウィンドウにフォーカスが移動するフォーカス・モデルです。
Java SE 7のXAWTではfocus-follows-mouseモデルは検出されませんが、これにより、単純なウィンドウ(java.awt.Window
クラスのオブジェクト)で問題が発生します。そのようなウィンドウにはoverride-redirect
プロパティが設定されているため、ウィンドウにフォーカスを移動できるのはマウス・ボタンを押した場合のみであり、ウィンドウの上にマウスを移動してもフォーカスは移動しません。回避方法としては、ウィンドウにMouseListener
を設定し、マウスがウィンドウのボーダーを横切ったときにウィンドウへのフォーカスを要求します。
ドラッグ・アンド・ドロップ(DnD)およびカット・アンド・ペースト/コピー・アンド・ペースト(CCP)操作をアプリケーションに追加できるようにする、データ転送機能に関連して発生する可能性のある問題。
次の項では、データ転送機能で発生する可能性がある問題について説明します。
ドラッグ・アンド・ドロップ(DnD)アプリケーションの問題のトラブルシューティングに使用できる方法。
デバッガを使用してDnD機能をトラブルシューティングするのは困難です。ドラッグ・アンド・ドロップ操作中はすべての入力がグラブされるからです。そのため、DnDの操作中にブレークポイントを入れた場合は、Xサーバーの再起動が必要になることがあります。かわりに、リモート・デバッグを使用してみてください。
DnDに関するほとんどの問題のトラブルシューティングには、2つの単純な方法を使用できます。
スプラッシュ画面の問題、ポップアップ・メニューの問題、背景色の継承など、AWTのその他の問題のトラブルシューティング。
次の各項では、他の問題をトラブルシューティングするためのヒントについて説明します。
トレイ・アイコンで発生する可能性がある問題。
Windows 98のJava SE 6リリースではTrayIcon.displayMessage()メソッドがサポートされていませんが、これは、バルーン表示用のネイティブ・サービスがWindows 98でサポートされていないからです。
SecurityManager
がインストールされている場合、TrayIcon
オブジェクトを作成するには、AWTPermission
の値がaccessSystemTray
に設定される必要があります。
ポップアップ・メニューで発生する可能性がある問題。
JPopupMenu.setInvoker()メソッドで、呼出し元(invoker)とは、ポップアップ・メニューの表示先となるコンポーネントのことです。このプロパティがnull
に設定されていると、ポップアップ・メニューが正しく機能しません。
解決方法は、ポップアップの呼出し元を自分自身に設定することです。
アプリケーションの一貫性をすべてのプラットフォームで確保するには、すべてのコンポーネントやコンテナで、明示的なカラー割り当て(背景と前景の両方)を使用してください。
多くのAWTコンポーネントでは、背景色や前景色として、親の色ではなく独自のデフォルトが使用されます。
この動作はプラットフォームに依存しています。つまり、プラットフォームが異なれば、同じコンポーネントでも違った動作になることがあります。また、コンポーネントの中には背景色または前景色のどちらか一方にはデフォルト値を使用するが、もう一方の色については親の値を取るものもあります。
AWTのコンテナにはサイズの制限があります。ほとんどのプラットフォームでは、この制限は32,767ピクセルです。
したがって、たとえばキャンバス・オブジェクトの高さが25ピクセルであれば、Java AWTパネル上に1310個を超える数のオブジェクトを表示することはできません。
残念ながら、この制限を変更する方法はなく、Javaコードやネイティブ・コードを使用しても変更できません。この制限は、オペレーティング・システムでウィジェット・サイズの格納に使用されるデータの型に依存します。たとえば、Windows 2000/XPオペレーティング・システムやLinuxオペレーティング・システムではinteger
型が使用されるため、整数の最大サイズが制限値となります。他のオペレーティング・システムでは、long
など別の型が使用されている可能性があり、この場合であれば制限は高くなります。
ご使用のプラットフォームのドキュメントを参照してください。
役立つ可能性のあるこの制限の回避方法の例を次に示します。
特定のグラフィカル・ユーザー・インターフェイス(GUI)コンポーネントのデバッグ時に-Dsun.awt.disablegrab=true
システム・プロパティを設定します。
特定のグラフィカル・ユーザー・インタフェース(GUI)のアクションでは、そのアクションを終了させるタイミングを決めるために、すべての入力イベントをグラブする必要があります(ポップアップ・メニューの移動など)。占有が続いている間は、ほかのアプリケーションは入力イベントを一切受け取りません。Javaアプリケーションのデバッグ時に、グラブがアクティブの間にブレークポイントに達すると、オペレーティング・システムがハングアップしたようになります。これは、グラブを保持しているJavaアプリケーションがデバッガによって停止され、入力イベントを一切処理できなくなったために起こります。他のアプリケーションは、このインストールされたグラブが原因でイベントを受け取りません。そのようなアプリケーションのデバッグを可能にするには、デバッガからアプリケーションを実行する際に次のシステム・プロパティを設定するようにしてください。
-Dsun.awt.disablegrab=true
このプロパティにより事実上、グラブの設定がオフになるので、システムがハングアップしなくなります。ただし、このオプションが設定されていると、場合によっては、通常であれば終了するはずのGUIアクションが終了できなくなります。たとえば、ウィンドウのタイトル・バーをクリックしてもポップアップ・メニューが終了しない可能性があります。
サードパーティ・ソフトウェア(特にMetacityなどのウィンドウ・マネージャ)から課される制限のため、toFront()/toBack()メソッドが予想どおりに機能せず、他のトップレベル・ウィンドウとの関係におけるウィンドウのスタック順序が変更されない可能性があります。
詳細については、CR 6472274を参照してください。
アプリケーションでウィンドウが手前に表示されるようにする場合は、まずWindow.setAlwaysOnTop(true)を呼び出して一時的にウィンドウが常に手前に表示されるようにしてから、setAlwaysOnTop(false)を呼び出して「常に手前に表示」の状態をリセットすることで、この問題の回避を試みることができます。
注意:
ウィンドウ・マネージャから課される制約が強化される可能性があるため、この回避方法の動作は保証されません。また、ウィンドウを「常に手前に表示」に設定できるのは信頼できるアプリケーションのみです。サンドボックスで実行されている署名なしのアプレットまたは署名なしのWeb StartアプリケーションはこのAPIを使用できないため、この問題を回避できません。
ただし、ネイティブ・アプリケーションも似た問題に悩まされているので、この特殊性により、Javaアプリケーションの動作はネイティブ・アプリケーションと似たものになっています。