TITLE:UIManagerで使用するFontを統一

Posted by at 2003-10-27

UIManagerで使用するFontを統一

`Swing`の各種コンポーネントで使用する全てのフォントを一気に変更します。

  • &jnlp;
  • &jar;
  • &zip;
FontChange.png

サンプルコード

private void updateFont(final Font font) {
  FontUIResource fontUIResource = new FontUIResource(font);
  for(java.util.Map.Entry<?,?> entry: UIManager.getDefaults().entrySet()) {
    if(entry.getKey().toString().toLowerCase().endsWith("font")) {
      UIManager.put(entry.getKey(), fontUIResource);
    }
  }
  //SwingUtilities.updateComponentTreeUI(this);
  recursiveUpdateUI(this);
  frame.pack();
}
private void recursiveUpdateUI(JComponent p) {
  for(Component c: p.getComponents()) {
    if(c instanceof JToolBar) {
      continue;
    }else if(c instanceof JComponent) {
      JComponent jc = (JComponent)c;
      jc.updateUI();
      if(jc.getComponentCount()>0) recursiveUpdateUI(jc);
    }
  }
}
View in GitHub: Java, Kotlin

解説

上記のサンプルでは、ツールバーのボタンでコンポーネントが使用するフォントを切り替えています。ただしツールバーだけは、`UIupdate`(フォントの変更)を除外しています。

全部のコンポーネントではなく、例えばテーブルのフォントだけ変更したい場合は以下のように設定します。

UIManager.put("Table.font", new FontUIResource(font));

`UIManagerから、UIDefaults`のキー一覧を作るなどして、いろいろ検索してみてください。

//キー一覧の作成例
import java.util.Map;
import javax.swing.UIManager;
class Test {
  public static void main(String[] args) {
    //for(Object o:UIManager.getDefaults().keySet()) //は、うまくいかない?
    //for(Object o:UIManager.getLookAndFeelDefaults().keySet())
    for(Map.Entry<?,?> entry: UIManager.getDefaults().entrySet())
      System.out.println(entry.getKey());
  }
}

この方法は、一々LookAndFeelを作成してフォントを変更するのが面倒なときには便利です。LookAndFeelを自作する場合は、以下などを参考にしてみてください。


`Metalで使用されているフォントが気に入らないといった場合は、システムLook&Feelを使用するか、Metal`でボールドフォントを無効にするなどの方法があります。

  • `MetalLookAndFeelではなく、SystemLookAndFeel`を使用する
try{
  UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}catch(Exception e) {
  e.printStackTrace();
}
UIManager.put("swing.boldMetal", Boolean.FALSE);

combo.setFont(font);
//以下回避方法
combo.setPrototypeDisplayValue(null); //null:default?
//or combo.firePropertyChange("prototypeDisplayValue",0,1); //0,1:dummy

特定のインスタンスだけ、`LookAndFeelなどを変更しても常に独自のフォントを設定したい場合、JComponent#updateUI()`をオーバーライドして設定する方法もあります。

JLabel label = new JLabel() {
  @Override public void updateUI() {
    super.updateUI();
    setFont(...);
  }
};

参考リンク

コメント

  • `JFileChooserインスタンス化前に上記ソースを実行すると ConcurrentModificationExceptionがスローされるのですが... 「JDK1.4.2_02`」プロパティーが動的に変化するとしたらあまり有効な方法でないのでは? -- MT
  • 割と手軽なので重宝するのですが、ちゃんとスレッド処理考えたほうがいいのかもしれませんね。 -- aterai
  • レスありがとうございます _ _)m とりあえず `Container を辿りながら含まれている Component 毎に setFont` 呼ぶようなユーティリティ用意してしのいでいます^^; -- MT
  • `UIManager`のリストにないコンポーネント(独自で作成したボタンなどのコンポーネント)なども追加すると変更が適用されるのでしょうか? -- mari
  • `JBottunなどのSwing`コンポーネントを継承していれば変更されるはずです。 -- aterai
  • レスありがとうございます。その場合、独自のコンポーネントを追加すると、そのコンポーネントのみ変更が適用されますか?`Panelを追加したら全てのpanel`に適用されてしまってうまくいきませんでした。良い方法があったら教えてください。 -- mari
  • すべてのコンポーネントに一々設定するのが面倒な場合のための方法なので、上記の場合は使用する意味が無いですね(^^;。ある独自コンポーネントのみフォントを変えたいのなら、コンストラクタなどで普通に`setFont`すればいいのでないかと思うのですが、どうなんでしょう?そうじゃなくて、あるパネル以下のコンポーネントのフォントを一気に変えたいということなんでしょうか? -- aterai
  • たびたびすみません。全体のフォントの大きさをツールバーの選択によって変化させるようにしたいです。フォントだけ変化させたいのですが、コンストラクタなどで勝手に`setBackgroundしているコンポーネントはLook and Feelで設定しているデフォルトのbackgroundに変わってしまいました。またnewするわけではないので、そのコンポーネントのみののデフォルトをどこかで設定できたらいいなー、と思いました。Look and Feelでもpanelだったらpanel`全ての設定しかできないのでしょうか?有効な方法があったら教えてください。よろしくお願いいたします。 -- mari
  • `Look and Feel`で変更するのではなく、イベントリスナーを作って実装するのはどうでしょう?はずしてるかもしれませんが、とりあえずサンプル置いておきます。初期値はコンストラクタで指定してます。ツールバーじゃなくてメニューで、フォントを切り替えてます。コンボボックスを切り替えたときにサイズがおかしいのは愛嬌ということで…。 -- aterai
  • すばらしいサンプルありがとうございます!参考にさせていただきました☆フォントの変更を`Look and Feelで行って、残りの描画できなかった背景色などをPropertyChangeListenerを`実装して描画しなおす、という方法も考えたのですが、こちらでも問題ないでしょうか?主題から外れてしまって申し訳ありません・・・。 -- mari
  • 次のネタ用にイベント作っただけなので、`PropertyChangeListener使うのはまったく問題ないと思います。むしろちゃんとJavaBeansにしてPropertyChangeListener`使うほうがいいかもしれません(^^;。 -- aterai
  • updateUI()をオーバーライドする方法を追記。 -- aterai