トップ 差分 一覧 ソース 置換 検索 ヘルプ PDF RSS ログイン

Swing、AWT全般

 Swingコンポーネントの構成

http://feather.cocolog-nifty.com/weblog/2007/10/swing_swing2_ro_34ad.html
Swingのフレームを構成するレイヤーの構成は以下のとおり。

 エンターキーでボタンを選択する

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が呼ばれる。

よって、フォーカスの移動元、移動先が共に
JComponentのサブクラスのである必要がある。
早い話が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 を呼ぶようにする。

 メニュー展開の例

メニューからFrameを開く例.zip(661)

Dialog に

setUndecorated(true);

して、ロード中を画像にしたもの。
メニューからFrameを開く例2.zip(708)

  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の下端左側のほぼ外側位置、漢字候補表示は当該ひらがな表示位置の下側位置

フォントが荒い

環境によってフォントのアンチエイリアスが荒いときがある。
ディスプレイの解像度が高い場合に、OSで拡大率を指定している場合にJavaFXのフォントが荒くなっているように思う。
起動オプションで以下のように倍率を指定するとアンチエイリアスがきれいになる。倍率は1.0とか1.5とか2.0のように指定する

-Dsun.java2d.uiScale=1.0


[カテゴリ: プログラミング言語 > Java]

[通知用URL]



  • Hatenaブックマークに追加
  • livedoorクリップに追加
  • del.icio.usに追加
  • FC2ブックマークに追加

最終更新時間:2023年04月14日 23時13分17秒