概要

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

サンプルコード

private void updateFont(final Font font) {
  FontUIResource fontUIResource = new FontUIResource(font);
  for (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 all

解説

上記のサンプルでは、ツールバーのボタンでコンポーネントが使用するフォントを切り替えています。ただしツールバーだけは、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());
  }
}

Metalで使用されているフォントが気に入らないだけなら、システムLookAndFeelを使用するか、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
  • JButtonなどの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
  • Nimbusの場合は、この方法では駄目でした。バグのようです。回避策は、UIManager.getLookAndFeelDefaults().put("defaultFont", new Font(Font.SANS_SERIF, 0, 20));をフレームをnewする前に実行する事でした。 参考:swing - Java: Altering UI fonts (Nimbus) doesn't work! - Stack Overflow -- 匿名