トップ 一覧 置換 検索 ヘルプ RSS ログイン

Swing、AWT全般の変更点

  • 追加された行はこのように表示されます。
  • 削除された行はこのように表示されます。
!!Swingコンポーネントの構成
http://feather.cocolog-nifty.com/weblog/2007/10/swing_swing2_ro_34ad.html
Swingのフレームを構成するレイヤーの構成は以下のとおり。
{{img ui-rootPane.gif}}

!!エンターキーでボタンを選択する
 KeyStroke enterPress = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false);
 KeyStroke enterRelease = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, true);
  
 button.getInputMap().put(enterPress, "pressed");
 button.getInputMap().put(enterRelease, "released");

!!フォントのアンチエイリアス
http://itpro.nikkeibp.co.jp/article/COLUMN/20070205/260649/
http://d.hatena.ne.jp/itiri/20080224/1203856116

!Java6の場合
 awt.useSystemAAFontSettings
オプションを使う。
設定出来る値は
,,
,off      ,アンチエイリアスを行わない
,on       ,アンチエイリアスを行う
,gasp     ,小さい文字ではアンチエイリアスを行わない
,lcd      ,サブピクセルのアンチエイリアス
,lcd_hrgb ,サブピクセルのアンチエイリアス 横方向RGB
,lcd_hbgr ,サブピクセルのアンチエイリアス 横方向BGR
,lcd_vrgb ,サブピクセルのアンチエイリアス 縦方向RGB
,lcd_vbgr ,サブピクセルのアンチエイリアス 縦方向BGR
デフォルトでは、gaspになっているみたい。

例(実行時):
 java -Dawt.useSystemAAFontSettings=on test.class
例(プログラム内):
 System.setProperty("awt.useSystemAAFontSettings","on");

!Java5の場合
 swing.aatext
オプションを使う。
例(実行時):
 java -Dswing.aatext=true test.class
例(プログラム内):
 System.setProperty("swing.aatext","true");


!!Look and Feel を変更する
http://terai.xrea.jp/Swing/LookAndFeel.html

 private static final String mac     = "com.sun.java.swing.plaf.mac.MacLookAndFeel";
 private static final String metal   = "javax.swing.plaf.metal.MetalLookAndFeel";
 private static final String motif   = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
 private static final String windows = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
 private static final String gtk     = "com.sun.java.swing.plaf.gtk.GTKLookAndFeel";
 private static final String nimbus  = "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel";
 private void setLookAndFeel(String laf) {
   try{
     UIManager.setLookAndFeel(laf);
     //SwingUtilities.updateComponentTreeUI(frame);
   }catch(Exception ex) {
     ex.printStackTrace();
   }
 }


!!フォントを一括で変更する
http://guijava.180r.com/p%A5%D5%A5%A9%A5%F3%A5%C8%A4%F2%B0%EC%B3%E7%CA%D1%B9%B9%A4%B9%A4%EB.html
 Font font = new Font("SansSerif",Font.PLAIN,18);
 LookAndFeel laf = UIManager.getLookAndFeel();
 Set keys = laf.getDefaults().keySet();
 for (Iterator it = keys.iterator(); it.hasNext();) {
	String key=it.next().toString();
	if (key.indexOf("font") != -1) {
		UIManager.put(key, font);
	}
 }

!!JDialog などからタイトルバーなどの枠を消す
 dialog.setUndecorated(true);
とすると、タイトルバーなどが無い JDialog が作成できる。

!!JFrameを中央に表示する
http://terai.xrea.jp/Swing/CenterFrame.html
 JFrame frame = new JFrame("フレームをスクリーン中央に表示");
 frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
 frame.getContentPane().add(new MainPanel());
 frame.pack();
 frame.setLocationRelativeTo(null);
 //以下は自前で位置を計算する場合
 //Rectangle screen = frame.getGraphicsConfiguration().getBounds();
 //frame.setLocation(screen.x + screen.width/2  - frame.getSize().width/2,
 //                  screen.y + screen.height/2 - frame.getSize().height/2);
 frame.setVisible(true);


!!デフォルトボタン
どこにフォーカスがあっても、エンターキーを押されたときに反応する
ボタン(デフォルトボタン)を設定するには
 JRootPane#setDefaultButton(JButton defaultButton) 
を使う。

!!JLabelの色が親パネルと同じになってしまう
 setOpaque(true)
にすると透過しない。逆に
 setOpaque(false)
にすると透過(親パネルと同じ色)になる。

!!swingコンポーネントで入力制限
[[Swingコンポーネントで入力制限]]

!!swingコンポーネントのイベントを他コンポーネントにスルーさせる
[[Swingコンポーネントのイベントをスルーさせる]]

!!awtイベントが全て終了してから処理をする
 SwingUtilities.invokeLater
 または
 Toolkit.getDefaultToolkit().getSystemEventQueue().invokeLate
を使う。
基本的にどちらも同じイベントディスパッチスレッドにイベントを追加する・・・はず。

!!awtイベントの終了を待つ
  SwingUtilities.invokeAndWait
 または
 Toolkit.getDefaultToolkit().getSystemEventQueue().invokeAndWait
を使う。

こんな感じでメソッド作っても良いかも。
 protected void waitDoEvent(){
    try {
      if (!EventQueue.isDispatchThread()){
        // Thread.sleep(100);  これだけでも良いような気がする・・・。
        SwingUtilities.invokeAndWait(new Runnable(){
            public void run(){
            }
        }); 
      }
    }  catch (Exception e){}
 }


!!ボーダー
!BorderFactory を使う
javax.swing.BorderFactory を使うと便利。
 createTitledBorder("hoge") ;
とか。

!javax.swing.border のクラスを使う
javax.swing.border のボーダークラスを使うと色々な線をコンポーネントの周りに描ける。
 LineBorder.createBlackLineBorder() 
とか
 new TitledBorder(LineBorder.createBlackLineBorder() , "タイトル")
 
ボーダーの周りに隙間を空けたい場合は、EmptyBorderを使う。
 label = new JLabel("ラベルだよ");
 Border margin = new EmptyBorder(0,5,0,5);
 label.setBorder(new CompoundBorder(LineBorder.createBlackLineBorder(), margin)); 
みたいな感じ。

!!InputVerifier のタイミング
JComponent を継承しているコンポーネント間でフォーカスを移動使用としたときに、
フォーカスの移動元のコンポーネントのInputVerifier に対して、verifiyが呼ばれる。

よって、フォーカスの移動元、移動先が共に
{{word JComponentのサブクラスのである必要がある。,red}}
早い話がSwingコンポーネント以外が画面にいると正常に動かない可能性有り。

!!モーダルについて
!親子関係ない場合
・モーダルが複数表示された場合、基本的にあとに表示されたほうが前面に出る。
!親子関係がある場合
・子は常に親の前面に表示される。
・親が非表示になると子も非表示になる

!!Swing コンポーネントの描画について
!update と repaint
*Swing では、update は呼ばれない。
*repaint イベントディスパッチャ以外から呼んでも良い。(イベントディスパッチャに再描画を依頼するのが repaint メソッド)

!Swingのペイントの処理過程
Swingが行う"リペイント"リクエストの処理は、AWTとやや違います。ただし、アプリケーションプログラムにとって、その最終結果はどちらも基本的に同じです--つまりpaint()が呼び出されます。SwingはRepaintManager API(後述)を使ってリペイントリクエストを処理し、ペイントの実行性能を上げています。Swingのペイントは、次のような二つの過程をたどります:

(A)ペイントリクエストが最初の親(最外側のウィンドウコンテナ)である重量コンポーネント(通常はJFrame, JDialog, JWindow,またはJApplet)に来たとき:

  イベントディスパッチスレッド(event dispatching thread, EDT, JavaのGUIが動いているスレッド)が、その重量コンポーネントのpaint()を呼び出す

  Container.paint()のデフォルトの実装が子の軽量コンポーネントのpaint()を再帰的に呼び出す

  最初のSwingコンポーネントに到着したら、JComponent.paint()のデフォルトの実装が次の処理を行う:

    コンポーネントのdoubleBufferedプロパティがtrueで、そのコンポーネントのRepaintManagerがダブルバッファリングをonにしていたら、Graphicsオブジェクトをオフスクリーンのグラフィクスに変換する.
    paintComponent()を呼び出す(ダブルバッファリングonならオフスクリーンのグラフィクスを渡して)
    paintBorder()を呼び出す(ダブルバッファリングonならオフスクリーンのグラフィクスを渡して)
    paintChildren()を呼び出す(ダブルバッファリングonならオフスクリーンのグラフィクスを渡して). これはクリップ領域とopaqueおよびoptimizedDrawingEnabledを使って、paint()を再帰的に呼び出すべき子のコンポーネントを判断します.
    コンポーネントのdoubleBufferedプロパティがtrueで、そのコンポーネントのRepaintManagerがダブルバッファリングonなら、元のオンスクリーンのGraphicsオブジェクトを使ってオフスクリーンの画像をコピーする.

  注: JComponent.paint()のステップ#1と#5は、paint()の再帰的な呼び出し(上のステップ#4で述べているpaintChildren()からの呼び出し)では行われません。ダブルバッファリングでは、一つの同じオフスクリーンイメージを一つのウィンドウ階層中のすべての軽量コンポーネントが共用するからです。 

(B)ペイントリクエストがjavax.swing.JComponentのサブクラスへのrepaint()呼び出しから来たとき:

  JComponent.repaint()は非同期のリペイントリクエストをコンポーネントのRepaintManagerに登録し、RepaintManagerはinvokeLater()を使ってRunnableをキューに入れ、あとでそのリクエストをイベントディスパッチスレッドの上で処理する.

  そのRunnableオブジェクトがイベントディスパッチスレッドの上で実行されると、コンポーネントのRepaintManagerがそのコンポーネントのpaintImmediately()を呼び出す. このメソッドは次のことを行う:

    クリップ領域とopaqueおよびoptimizedDrawingEnabled プロパティを使って、ペイント操作を開始する‘ルート’のコンポーネントを判断する(透明性とコンポーネントの重なりを正しく扱うため).
    ルートコンポーネントのdoubleBufferedプロパティがtrueで、ルートのRepaintManagerの上でダブルバッファリングがonなら、Graphicsオブジェクトをオフスクリーンのグラフィクスに変換する.
    ルートコンポーネントのpaint()を呼び出す(それがさらに、上の(A)のJComponent.paint()のステップ#2-4を実行する)--これにより、ルートの中にあってクリップ矩形に含まれるものすべてがペイントされる.
    ルートコンポーネントのdoubleBufferedプロパティがtrueで、ルートのRepaintManagerの上でダブルバッファリングがonなら、オフスクリーンの画像(オフスクリーンイメージ)を元のオンスクリーンのGraphicsオブジェクトを使ってコンポーネントにコピーする.

  注: 一つのコンポーネントやその親のどれかに対して複数のrepaint()呼び出しが行われると、これらの複数の呼び出しが、今repaint()が呼び出されている最上位(いちばん上の親)のコンポーネントのpaintImmediately()への一回のコールバックにまとめられることがあります。たとえばJTabbedPaneの中にJTableがあって、この収容階層のそのほかのリペイントの処理中に両者が共にrepaint()を呼び出すと、この2つのrepaint()呼び出しはJTabbedPaneの一回のpaintImmediately()呼び出しとして処理され、そこから、両コンポーネントのpaint()が実行されます。 

したがってSwingのコンポーネントでは、update()は呼び出されません。

repaint()を呼び出すとpaintImmediately()が呼び出されますが、このメソッドはペイント"コールバック"ではないので、ペイントを行うコードをpaintImmediately()の中に書いてはいけません。というより、ふつう、paintImmediately()をオーバライドするような状況はほとんどありません。 

!ダブルバッファリング
http://www.02.246.ne.jp/~torutk/javahow2/swing.html#doc1_id199
http://wisdom.sakura.ne.jp/system/java/swing/swing8.html
http://homepage1.nifty.com/algafield/paint.html

Swingではルートコンポーネントの一部として子が描画される。
例えば、JPanelのpaintはJPanelの親コンポーネントを辿って行き、ContentPaneまたは、RootPaneがJPanelのpaintを呼ぶ。
そのため、ダブルバッファを行うためのsetDoubleBufferedはルートコンポーネントに設定しておけば良い。
基本的に、RootPaneもContentPaneもJPanelも標準ではダブルバッファリングは有効になっている。
この時、JPanel#repaint と JFrame#repaintの違いは描画範囲の違いであり、ダブルバッファの設定はルートコンポーネントに左右される。

とりあえず、ダブルバッファを行う場合は、関連コンポーネントをsetDoubleBuffered(true) にしておけば良い。

==例えば、JPanel をダブルバッファリングで描画する場合==
==(自前でダブルバッファリングを行うために、Swingのダブルバッファリングを止める場合)==
==*JPanel#repaint で再描画するときは、RootPane から JPanel まで全てのコンポーネントで setDoubleBuffered(false); する必要がある。==
==*JFrame#repaint で再描画する場合は、RootPane だけを setDoubleBuffered(false); すれば良い(らしい)。==
==いずれにしても、関連するものを setDoubleBuffered(false); しておけばいいと思う。==

ダブルバッファリングを無効にする場合は、関連コンポーネントのsetDoubleBuffered(false)を呼べば良い。

以下の方法でダブルバッファリングを無効にすることもできる。
 RepaintManager rm = RepaintManager.currentManager(component);
 rm.setDoubleBufferingEnabled(false);

ただし、各コンポーネントの描画はルートコンポーネントを行う挙動は変わらないので、
JPanelで自作ダブルバッファリングしてもチラツキは無くならないので注意。

!!キーボードニーモニックの設定
 setMnemonic(KeyEvent.VK_O);
とか

!!ウインドウを表示したときに、隠れてしまう
ウインドウを表示したときに、隠れてしまうことがある。
Dialog を消す際に、Dialog の親を消すことでDialog を消したりすると起きるようだ。
きちんと、Dialog の dispose を呼ぶようにする。

!!メニュー展開の例
{{ref メニューからFrameを開く例.zip}}

Dialog に 
 setUndecorated(true);
して、ロード中を画像にしたもの。
{{ref メニューからFrameを開く例2.zip}}

!! JList でスクロールバーの位置を移動させる
JScrollPane で スクロールバーを設定してある JList に対して
スクロールバーを移動したい時は
 ensureIndexIsVisible
を使う

!! JTable でスクロールバーの位置を移動させる
JScrollPane で スクロールバーを設定してある JTable に対して
スクロールバーを移動したい時は
 Rectangle rect = table.getCellRect(10,0, false);
 scrollpane.getViewPort().scrollRectToVisible( rect );
を使う

!!アニメgifについて
ImageIcon 等に利用する画像に アニメGIF を利用することができる。
ロード中などの表示に利用すると便利。

!!imeの表示位置
!Windows
Windows19では、
jdk8u131以降で sun.awt.windows.WInputMethod で エラーが発生するようになった(Google IMEの場合)
jdk8u121まではWindows10でも問題なし。

!Linux
https://lists.debian.or.jp/archives/debian-users/201609/msg00005.html
 ibus-anthy: ひらがな表示はtextfield内、漢字候補表示はGUI内の下端左側隅位置
 ibus-mozc: ひらがな表示はtextfield内、漢字候補表示はGUIの下端左側のほぼ外側位置
 fcitx-anthy: GUIの下端左側のほぼ外側位置に表示ブロックが形成され、かつその内側に矩形ラインが形成され、当該矩形ラインの内側にひらがな表示が行われ、spaceキーを押すと、別途表示ブロック及びその内側の矩形ラインが形成され、当該矩形ラインの内側に漢字候補表示が行われる。
 fcitx-mozc: ひらがな、漢字の何れも共に、GUIの下端左側のほぼ外側位置に出来る大きな表示ブロック内に表示される。
 uim-anthy: ひらがな表示はGUIの下端左側のほぼ外側位置、漢字候補表示は当該ひらがな表示位置の下側位置
 uim-mozc: ひらがな表示はGUIの下端左側のほぼ外側位置、漢字候補表示は当該ひらがな表示位置の下側位置

{{category2 プログラミング言語,Java}}