11 AWT

この章では、Java SE Abstract Window Toolkit (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

レイアウト・マネージャの問題

この項では、レイアウト・マネージャに関連して発生する可能性のある問題について説明し、回避方法がある場合はその方法を提供します。

レイアウト・マネージャおよび回避策で次の問題が発生します。
  1. invalidate()およびvalidate()を呼び出すとコンポーネントのサイズが増える

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

    回避方法: JDKでは、そのような場合にレイアウト・マネージャがコンポーネントを再配置する必要があるかどうかを検出する信頼できる簡単な方法がありませんが、簡単な回避方法が1つあります。次の例に示すように、現在必要なサイズを返すようにオーバーライドされるメソッドgetPreferredSize()を持つコンポーネントを使用します。

    public Dimension getPreferredSize(){
       return new Dimension(size+xpad*2+1, size+ypad*2+1); 
    }
    
  2. Container.doLayout()メソッドからvalidate()を呼び出すと、無限再帰が発生する

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

キー・イベント

キー・イベントの処理に関するいくつかの問題は、現在のリリースでは解決策がありません。

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

  • 一部の非英語キーボードでは特定のアクセント・キーがキーに刻印されているため、それらはプライマリ・レイヤーの文字になります。ところが、それらに対応するJavaキー・コードがないため、ニーモニックとして使用できません。

  • 実行時にデフォルトのロケールを変更しても、メニューのアクセラレータ・キーとして表示されるテキストが変更されません。

  • 標準109キー日本語キーボードでは、円記号キーとバックスラッシュ・キーのどちらの場合もバックスラッシュが生成されますが、これは両者のWM_CHARメッセージの文字コードが同じであるためです。AWTはそれらを区別すべきです。

モーダリティの問題

この項では、モーダリティの使用に関連する問題について説明します。

この項では、次の問題について説明します。

  • UNIXのウィンドウ・マネージャ:

    一部のLinux環境(共通デスクトップ環境(CDE)のウィンドウ・マネージャを使用する場合など)では、モーダリティの改善点の多くは使用できません。あるモーダリティ・タイプやモーダル除外タイプが特定の構成でサポートされているかどうかを確認するには、次のメソッドを使用します:

    • Toolkit.isModalityTypeSupported()

    • Toolkit.isModalExclusionTypeSupported()

    モーダル・ダイアログ・ボックスが画面に表示されると、ウィンドウ・マネージャは同じアプリケーション内の一部のJavaトップレベル・ウィンドウがタスクバーに表示されないようにすることがあります。これはエンド・ユーザーを困惑させることがありますが、非表示になっているウィンドウはすべてモーダル・ブロックされていて操作できないため、ユーザーの作業に大きな影響はありません。

  • モーダリティのその他の問題:

    モーダリティ関連の機能とその使用方法の詳細は、AWTのモーダリティの仕様に関する項を参照してください。

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

AWTのクラッシュ

この項では、AWTに関連するクラッシュを識別してトラブルシューティングする方法について説明します。

  • AWTクラッシュの判別:

    クラッシュが発生すると、そのクラッシュの発生時に取得された情報や状態を含むエラー・ログが作成されます。「致命的エラー・ログ」を参照してください。

    このファイルの先頭付近の行には、エラーが発生したライブラリが示されます。次の例は、クラッシュが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に関係している可能性があります。

  • AWTクラッシュのトラブルシューティング:

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

    もう1つの例は、ネイティブのファイル・ダイアログに関するものです。オペレーティング・システムがこれらのダイアログを初期化して表示するまで多少の時間がかかるため、setVisible(true)を呼び出してすぐにそれらを破棄してしまうと、クラッシュが発生する可能性があります。したがって、アプリケーション内にいくつかの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は、マウスの下にあるウィンドウにフォーカスが移動するフォーカス・モデルです。

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

この項では、AWTのフォーカスに関連して発生する可能性のある問題および推奨される解決方法について説明します。

  1. KDEを実行するLinux上のXToolkitでは、フレームのタイトルをクリックしても、2つのフレーム間で切り替えることができない。

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

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

  2. [Tab]/[Shift]+[Tab]でフォーカスを移動するためにKeyListenerを使用してフォーカスを管理しても、キー・イベントが現れない。

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

  3. Window.setModalExclusionType(ModalExclusionType)でウィンドウがモーダル除外に設定される。

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

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

  4. Windowsで、コンポーネントがフォーカスを要求し、同時にそのコンテナから削除される。

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

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

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

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

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

  6. Windowsで、非アクティブなフレーム内のウィンドウをalwaysOnTopに設定すると、そのウィンドウはキー・イベントを受け取れない。

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

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

  7. スプラッシュ画面が表示され、そのスプラッシュ画面のウィンドウが閉じた後でフレームが表示されると、そのフレームはアクティブ化されない。

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

  8. WindowFocusListener.windowGainedFocus(WindowEvent)メソッドがフレームの直近のフォーカス所有者を返さない。

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

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

    ノート:

    このアプローチは、ウィンドウでは機能せず、フレームまたはダイアログ・ボックスでのみ機能します。

  9. Component.setEnabled(false)でウィンドウを無効にしても、完全にフォーカス不可能な状態にならない。

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

データ転送

次の項では、ドラッグ・アンド・ドロップ(DnD)およびカット・アンド・ペースト/コピー・アンド・ペースト(CCP)操作をアプリケーションに追加できるようにする、データ転送機能に関連して発生する可能性のある問題について説明します。

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

デバッガを使用してDnD機能をトラブルシューティングするのは困難です。ドラッグ・アンド・ドロップ操作中はすべての入力がグラブされるからです。そのため、DnDの操作中にブレークポイントを入れた場合は、Xサーバーの再起動が必要になることがあります。かわりに、リモート・デバッグを使用してみてください。

DnDに関するほとんどの問題のトラブルシューティングには、2つの単純な方法を使用できます。

  • すべてのDataFlavorインスタンスの出力
  • 受信されたデータの出力
    リモート・デバッグに代わる方法として、遅延なしで出力するSystem.err.println()関数があります。

データ転送に関するよくある問題

この項では、AWTのデータ転送操作で頻繁に発生する問題を説明し、そのトラブルシューティング方法を提示します。

  1. 大量のデータをクリップボードからペーストするのに時間がかかりすぎる。

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

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

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

    • DataFlavor[] getAvailableDataFlavors()

    • boolean isDataFlavorAvailable(DataFlavor flavor)

    • Object getData(DataFlavor flavor)

  2. JavaアプリケーションでDnD操作にTransferable.getTransferData()を使用すると、ドラッグに長い時間がかかるように思われる。

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

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

    解決方法: Transferableデータをキャッシュに入れて、一度しか生成されないようにします。

  3. JavaアプリケーションとGNOME/KDEデスクトップやファイル・ブラウザとの間でファイルを転送できない。

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

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

  4. DragGestureEventまたはDragSourcestartDrag()メソッドの1つに渡したイメージが、後続のDnD操作中に表示されない。

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

  5. DnDを使用して配列を移動する方法がない。

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

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

    解決方法: 次の例に示すように、表現クラスのパラメータの値を引用符で囲みます(引用符はエスケープします)。

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

    バグ・レポートを参照してください。

  6. SwingコンポーネントでAWTのDnDサポートを使用すると、問題が発生する。

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

    解決方法: SwingコンポーネントではSwingのDnDサポートを使用します。SwingのDnD実装はAWTのDnD実装に基づいていますが、SwingとAWTのDnDを混在させることはできません。Javaチュートリアルのレッスン: ドラッグ・アンド・ドロップおよびデータ転送に関する項を参照してください。

  7. ターゲットに依存するようにソースの状態を変更する方法がない。

    ターゲットに依存するようにソースの状態を変更するには、ソース・コンポーネントとターゲット・コンポーネントへの参照が同じコード領域内で必要になりますが、これは現時点ではDnD 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()の各メソッド内で、ターゲットとソースを取得できます。

  8. アプリケーション内でのオブジェクト転送に長い時間がかかる。

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

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

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

その他の問題

次の各項では、他の問題をトラブルシューティングするためのヒントについて説明します。

スプラッシュ画面の問題

AWTのスプラッシュ画面で発生する可能性がある問題と解決策。

この項では、AWTのスプラッシュ画面で発生する可能性のあるいくつかの問題を説明します。

  1. 適切なMANIFEST.MFを含むJARファイルを-classpathに指定しても、スプラッシュ画面が機能しない。
    解決方法: 次の問題の解決方法を参照してください。
  2. アプリケーションのいくつかのJARファイルのどれにスプラッシュ画面のイメージを含める必要があるかが明らかでない。
    解決方法: スプラッシュ画面のイメージがJARファイルから選択されるのは、-jarコマンド行オプションでJARファイルが使用された場合のみです。このJARファイルには、SplashScreen-Imageマニフェスト・オプションとイメージ・ファイルの両方を含めるようにしてください。-classpathのJARファイルのMANIFEST.MF内でスプラッシュ画面がチェックされることは決してありません。-jarを使用しない場合でも、コマンド行で-splashを使ってスプラッシュ画面のイメージを指定できます。
  3. 透明度PNGを使用したスプラッシュ画面がLinuxオペレーティング・システムで機能しない。
    解決方法: これは、X11のネイティブの制限です。Linuxオペレーティング・システムでは、半透明イメージのアルファ・チャネルが50%のしきい値と比較されます。アルファ値が0.5より高いピクセルは不透明に、アルファ値が0.5より低いピクセルは完全に透明になります。

トレイ・アイコンの問題

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アプリケーションの動作はネイティブ・アプリケーションと似たものになっています。

重量または軽量コンポーネントの混在

重量または軽量(HW/LW)コンポーネントの混在機能では、次の問題を扱います。

  • コンポーネント階層の有効化:

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

    component.setFont(myFont);
    frame.validate();
    
    framecomponentを含んでいるフレームのことです。

    ノート:

    SwingアプリケーションやSwingライブラリでは、多くの場合、次のパターンが使用されます。
    component.setFont(myFont);
    component.revalidate();
    

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

    コンポーネント階層全体の有効性を検証するには、「AWTのデバッグに関するヒント」で説明した[Ctrl]+[Shift]+[F1]というキーの組合せを使用できます。コンポーネントにinvalidというマークが付いている場合、validate()呼出しがどこかで欠落していることを示している可能性があります。

  • 有効なルート:

    コンポーネント階層の有効化のプロセスにかなりの時間を要することがあるため、プロセスの処理速度を上げるために、「コンポーネント階層の有効化」で説明した有効なルートという概念がSwingに取り入れられました。そのような最適化では階層の上位部分が無効のままになりますが、有効なルートの内側にあるコンポーネントのレイアウトはコンポーネント階層の外側(つまり、有効なルートの兄弟)のレイアウトに影響を与えないため、問題は起きませんでした。ただし、1つの階層内にHWコンポーネントとLWコンポーネントが混在している場合、この記述は当てはまらなくなります。そのため、この機能ではコンポーネント階層全体が有効になる必要があります。

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

    -Djava.awt.smartInvalidate=true
    

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

    component.revalidate();
    

    ノート:

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

    この最適化された新しいモードでアプリケーションを実行する際になんらかの問題が発生する場合は、「AWTのデバッグに関するヒント」で説明した[Ctrl]+[Shift]+[F1]というキーの組合せを使用することで、コンポーネント階層のどの部分が無効なままになっており、したがって問題の原因となっている可能性があるのかを調査できます。

  • Swingのペイントの最適化:

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

  • 不透明でないLWコンポーネント:

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

    ノート:

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

    一部の開発者は以前、HWコンポーネントとLWコンポーネントを混在させる必要がある場合に備えて、独自のサポートを実装しました。この組込み機能を無効にするには、アプリケーションの起動時に次のシステム・プロパティを指定する必要があります。

    -Dsun.awt.disableMixing=true