Trouble 8: Swing/AWTコンポーネントがうまく動きません
<Q8-1>フルスクリーン画面を表示する方法が分かりません。
ウィンドウをフルスクリーンで表示したいのですが、JFrameを使用するとタイトルバーが表示されてしまいます。
タイトルバーのないフルスクリーン画面は実現できないのでしょうか?
| <発生環境> |
| OS |
Any |
| JDK |
1.4 |
| Vender |
Any |
- <A8-1>
- JDK1.4でサポートされたフルスクリーン排他モード(Full-Screen Exclusive Mode)を利用することで実現可能です。
■フルスクリーン排他モードを利用したフルスクリーン画面の表示手順
(1) JWindowを継承してフルスクリーン表示したいウィンドウを作成する。
(2) GraphicsEnvironmentを取得する。
(3) GraphicsEnvironmentからGraphicsDeviceを取得する。
(4) GraphicsDeviceをフルスクリーン排他モードに変更する。
(5) GraphicsDeviceフルスクリーン排他モードを解除する。
※) フルスクリーン排他モードは画面への直接描画を行なうことにより画面描画性能を向上させる仕組みです。
フルスクリーン排他モードがサポートされていない環境の場合、JDKによりウィンドウのサイズをスクリーンサイズに変更して (0,0) に配置するというシミュレートが行なわれます。
■コード例
※コード中の(1)、(2)などの表記は上の実現方法の(1)、(2)などに対応します。
public class FullScreenTestVer
{
public static void main(String args[])
{
JWindow window = new JWindow()
{
public void paint(Graphics graphics)
{
graphics.setColor(Color.blue);
graphics.setFont(new Font(null, Font.BOLD, 80));
graphics.drawString("Hello, World!", 40, 100);
}
}; //(1) JWindowを継承して全画面表示したいウィンドウを作成する。
testGraphicsDevice(window);
}
/**
* 指定したウィンドウを、フルスクリーン排他モードに設定する。
* @param window 表示するwindow
*/
private static void testGraphicsDevice(Window window)
{
// (2) GraphicsEnvironmentを取得する。
GraphicsEnvironment graphicsEnvironment =
GraphicsEnvironment.getLocalGraphicsEnvironment();
// (3) GraphicsEnvironmentからGraphicsDeviceを取得する。
GraphicsDevice graphicsDevice = graphicsEnvironment.getDefaultScreenDevice();
// (4) フルスクリーン排他モードに変更する。
graphicsDevice.setFullScreenWindow(window);
try
{
Thread.sleep(3000);
}
catch (InterruptedException iex)
{
;
}
// (5) フルスクリーン排他モードを解除する。
graphicsDevice.setFullScreenWindow(null);
System.exit(0);
}
}

<Q8-2>Windows98上で、JDialogを閉じる時に一般保護違反例外が発生してしまいます。
例外がIMM32.DLLで発生しています。
| <発生環境> |
| OS |
Windows |
| JDK |
JDK1.3.0 |
| Vender |
Sun |
<Q8-3>一部機種(またはグラフィックスチップ?詳細は未調査)において、Swingコンポーネントの再描画が正しく行われません。
| <発生環境> |
| OS |
Windows |
| JDK |
JDK1.2.2/JDK1.3.0 |
| Vender |
Sun |
<Q8-4>JTextFiledでIME2000を使用して文字を入力中にF5キーを押すとコンソールに大量のトレースが出力されてしまいます。
Windows98において、javawを使用して起動したjavaプロセスの場合、コンソールバッファが詰まってプログラム動作が停止してしまいます。(Q5-3に関連)
| <発生環境> |
| OS |
Windows |
| JDK |
JDK1.3.0 |
| Vender |
Sun |
<Q8-5>画面を(比較的速いスピードで)閉じたり開いたりしていると、その画面に設定されていたフォーカスが消えてしまいます。
再現頻度:1時間ほど画面のオープンクローズを繰り返しつづけて1回出るか出ないかです。
| <発生環境> |
| OS |
Windows98 |
| JDK |
JDK1.3 |
| Vender |
Sun |
- <A8-5>
- 原因不明です。
仕様として、「画面を開いた際のデフォルトフォーカス」というものを設け、setVisibleされた際に必ずそのコンポーネントにフォーカスを当てることで解決できます。
<Q8-6>JFrameをsetEnabled(false)で使用不可にしても、その中に含まれるコンポーネントは使用できてしまいます。
たとえば、マウスカーソルがテキストフィールドにある状態で、上記のように使用不可にしても、テキストが入力できてしまいます。
| <発生環境> |
| OS |
Windows2000/NT |
| JDK |
JDK1.3 |
| Vender |
Sun |
- <A8-6>
- JFrameのsetEnabledをオーバーライドし、中に含まれる全てのコンポーネントのsetEnabledメソッドを呼ぶようにすることで解決できます。
<Q8-7>JButtonのフォーカスが外れていても、Enterキーを押すと、そのボタンが押されたような動きをしてしまいます。
Look&FeelがWindowsの場合のみに発生します。
| <発生環境> |
| OS |
Windows2000/NT |
| JDK |
JDK1.3 |
| Vender |
Sun |
- <A8-7>
- そのJButtonが、その画面のデフォルトボタンになっているためです。
setDefaultCapable(false)で解除すれば、この現象は出なくなります。
<Q8-8>JTextField(JPasswordField)で、スクロールが開始される文字数の文字を入力すると、カーソル(キャレット)が残ったままスクロールされてしまいます。
しかし、再描画を行うと、カーソルは消えます。
| <発生環境> |
| OS |
Windows2000/NT |
| JDK |
JDK1.3 |
| Vender |
Sun |
<Q8-9>JMenuBarの要素が空の画面で、F10キーを押下すると、ArrayIndexOutOfBoundsExceptionが発生してしまいます。
| <発生環境> |
| OS |
Windows2000/NT |
| JDK |
JDK1.3 |
| Vender |
Sun |
- <A8-9>
- JMenuBarの要素が無い場合は、JFrameにaddしないようにすることで解決できます。
<Q8-10>ポップアップメニュー(カスケードメニュー)を表示させてから一度選択すると、次回選択時にNullPointerExceptionを出力し、正常に動作しません。
| <発生環境> |
| OS |
WindowsNT4 |
| JDK |
JDK1.3 |
| Vender |
Sun |
<Q8-11>モーダレスダイアログを表示すると、親画面が操作不能になってしまう場合があります。
| <発生環境> |
| OS |
Windows2000 |
| JDK |
JDK1.3 |
| Vender |
Sun |
- <A8-11>
- 親画面を最小化した状態でモーダレスダイアログ(ダイアログを閉じなくても親画面を操作できる)を開くと、ダイアログを閉じるまで親画面を最大化することができません。
最小化されているウィンドウを親とするダイアログを開く場合、親ウィンドウを通常サイズに戻す、といった対応が必要になります。
<Q8-12>モーダルダイアログを表示すると、一部の画面だけでなく、表示中の全画面が操作不能になってしまいます。
| <発生環境> |
| OS |
WindowsNT4,WindowsXP |
| JDK |
JDK1.3,JDK1.4 |
| Vender |
Sun |
- <A8-12>
- Swingのモーダルダイアログは、特定の画面に対しては働かず、全画面に対してモーダルになってしまいます。
回避策としては、Swingのモーダル機能は用いず、すべてモーダレスにして、自分自身で親画面を選択不可にする方法があります。
<Q8-13>Solarisにて、WindowsスタイルのLook&Feelが正しく設定できません。
以下の設定が行えません。
javax.swing.UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
| <発生環境> |
| OS |
Solaris |
| JDK |
JDK1.3.1 |
| Vender |
Sun |
- <A8-13>
- 現在、WindowsスタイルのLook&Feelについては、Win32環境でのみサポートされています。 従って、Solaris上で利用することはできません。
Look&Feelのサポート状況については、SunのSwingチュートリアルを参照してください。
<Q8-14>JTreeのToolTipText表示処理にて、NullPointerExceptionが発生します。
発生する例外は以下の通りです。
java.lang.NullPointerException
at javax.swing.JTree.getPathForLocation(JTree.java:1702)
at javax.swing.JTree.getRowForLocation(JTree.java:1721)
at javax.swing.JTree.getToolTipText(JTree.java:1009)
at javax.swing.ToolTipManager.mouseMoved(ToolTipManager.java:522)
(以下省略)
| <発生環境> |
| OS |
WindowsNT4 |
| JDK |
JDK1.3.1 |
| Vender |
Sun |
<Q8-15>JTextFieldで入力フィールド長を超える文字入力を行うと、既存文字が上書きされてしまいます。
日本語など、IMを介して文字を入力する場合に発生します。
| <発生環境> |
| OS |
WindowsNT4 |
| JDK |
JDK1.3 |
| Vender |
Sun |
- <A8-15>
- IM利用中におけるフィールド長制限が適切に機能していないのが原因です。IM利用中の未確定文字の場合は、設定フィールド長をオーバーしても入力できるようにし、入力文字確定処理時に最大フィールド長分で文字を切るように変更することで、上書きを回避できます。
<Q8-16>JTextAreaにフォーカスがある状態で、TABキーによるコンポーネント間のフォーカス遷移ができません。
| <発生環境> |
| OS |
Windows98SE / WindowsXP |
| JDK |
JDK1.3 / JDK1.4 |
| Vender |
Sun |
- <A8-16>
- JTextAreaは、テキストエリア内のTAB文字入力を可能にする為、TABキーでフォーカスイベントを発生させないように実装されています。ただし、Ctrl+TABでフォーカス遷移が可能です。
TABキーのみでコンポーネント間のフォーカス遷移を行いたい場合は、JTextAreaにKeyListenerを追加することで挙動を変更可能です。
KeyListener#keyPressed()でKeyEventオブジェクトからキーコードを取得し、TABキーである場合にはComponent#transferFocus()を呼び出します。
<Q8-17>JFrameのsetBackground()で背景色を設定しても、フレームの背景色が変更されません。
| <発生環境> |
| OS |
any |
| JDK |
any |
| Vender |
any |
- <A8-17>
- JFrameはコンポーネントを配置するためにContentPaneと呼ばれるコンテナを使用します。JFrameの背景色はこのContentPaneの背景色に依存します。
なお、ContentPaneはContainerの拡張であり、通常はJPanelです。
JFrameの背景色を変更する場合は以下のように記述する必要があります。
JFrame frame;
frame.getContentPane().setBackground(<RGB>);
<Q8-18>JLabelのsetBackground()を利用して背景色を設定しても、ラベルの背景色が変更されません。
| <発生環境> |
| OS |
any |
| JDK |
any |
| Vender |
any |
- <A8-18>
- JLabelのOpaqueプロパティがデフォルトでfalse(透明)になっているためです。
JLabelの背景色を変更する場合は以下のように設定します。
JLabel label;
label.setOpaque(true);
label.setBackground(<RGB>);
<Q8-19>Swingでsleep時間を設定しても、sleepされずに描画されます。
New!
Swingを利用して、「画面消去→sleep→再描画」という処理を行ったのですが、
再描画処理を行いません。
public void redraw(int x, int y){
// 消去処理
this.initialize();
this.view_.getFrame().repaint();
// sleep処理
Thread.sleep(1000);
// 描画処理
Rectangle2D rectangle = new Rectangle2D.Double(x, y, 1, 1);
・・・
this.view_.getFrame().repaint();
}
| <発生環境> |
| OS |
Any |
| JDK |
JDK5.0以降 |
| Vender |
Sun |
- <A8-19>
- Swingの仕様です。
Swingはイベント駆動で動作し、イベントキューと呼ばれるキューにためられます。
そして、このイベントキューからイベントを取り出してイベント処理を実行するのが
イベント・ディスパッチ・スレッドです。
Swingでは、このイベント・ディスパッチ・スレッドが描画処理も行います。
そのため、上記のようなプログラムを書いても、イベントキューにイベントが入るタイミングが異なるだけで、
描画処理が行われるときには、イベント取得→描画→イベント取得→描画、という処理が連続して行われます。
この問題を回避するためには、2つの処理を別スレッドに切り分けるなど、
イベント・ディスパッチ・スレッドによって行なわれる2つの描画処理が、
別のタイミングで行われるようにする必要があります。
注意:本文書の内容に誤りがあり、またこの文書によって不利益を被っても、
エスエムジー株式会社は一切関知いたしません。