TITLE:UIManagerで使用するFontを統一
Posted by terai at 2003-10-01

UIManagerで使用するFontを統一

Swingの各種コンポーネントで使用する全てのフォントを一気に変更します。JavaHouse-Brewers:49474 Re: setFont に関してから引用しています。
  • category: swing folder: FontChange title: UIManagerで使用するFontを統一 tags: [UIManager, Font] author: aterai pubdate: 2003-10-27 description: Swingの各種コンポーネントで使用する全てのフォントを一気に変更します。 image: https://lh4.googleusercontent.com/_9Z4BYR88imo/TQTNJ5XQrjI/AAAAAAAAAaU/lvxCohYLmBI/s800/FontChange.png

概要

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

#screenshot

サンプルコード

#spanend
#spanadd
* サンプルコード [#sourcecode]
#spanend
#spanadd
#code(link){{
#spanend
private void updateFont(final Font font) {
  FontUIResource fontUIResource = new FontUIResource(font);
  UIDefaults defaultTable = UIManager.getLookAndFeelDefaults();
  for(Object o: defaultTable.keySet()) {
    if(o.toString().toLowerCase().endsWith("font")) {
      UIManager.put(o, fontUIResource);
  // for (Map.Entry<?, ?> entry: UIManager.getDefaults().entrySet()) {
  UIManager.getLookAndFeelDefaults().forEach((key, value) -> {
    if (key.toString().toLowerCase(Locale.ENGLISH).endsWith("font")) {
      UIManager.put(key, fontResource);
    }
  }
  //SwingUtilities.updateComponentTreeUI(MainPanel.this);
  recursiveUpdateUI(MainPanel.this);
  });
  // SwingUtilities.updateComponentTreeUI(this);
  recursiveUpdateUI(this);
  frame.pack();
}
#spanadd

#spanend
private void recursiveUpdateUI(JComponent p) {
  for(Component c: p.getComponents()) {
    if(c instanceof JToolBar) {
  for (Component c: p.getComponents()) {
    if (c instanceof JToolBar) {
      continue;
    }else if(c instanceof JComponent) {
      JComponent jc = (JComponent)c;
    } else if (c instanceof JComponent) {
      JComponent jc = (JComponent) c;
      jc.updateUI();
      if(jc.getComponentCount()>0) recursiveUpdateUI(jc);
      if (jc.getComponentCount() > 0) {
        recursiveUpdateUI(jc);
      }
    }
  }
}

解説

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

解説

上記のサンプルでは、ツールバーのボタンでコンポーネントが使用するフォントを切り替えています。ただしツールバーだけは、UIupdate(フォントの変更)を除外しています。 全部のコンポーネントではなく、例えばテーブルのフォントだけ変更したい場合は以下のように設定します。
  • -
  • 全コンポーネントではなく、例えばJTableのフォントだけ変更したい場合はTable.fontをキーにして以下のように設定する
    UIManager.put("Table.font", new FontUIResource(font));
    
UIManagerのキー一覧を作るなどして、いろいろ検索してみてください。
  • 各コンポーネントのキーは、UIManagerからUIDefaultsのキー一覧が作成可能
    #spandel
    //キー一覧の作成例
    #spanend
    #spandel
    import java.util.*;
    #spanend
    #spandel
    import javax.swing.*;
    #spanend
    #spandel
    public class Test {
    #spanend
    #spanadd
    // キー一覧の作成例
    #spanend
    #spanadd
    import javax.swing.UIManager;
    #spanend
    #spanadd
    
    #spanend
    #spanadd
    class Test {
    #spanend
      public static void main(String[] args) {
        UIDefaults defaultTable = UIManager.getLookAndFeelDefaults();
        for(Object o: defaultTable.keySet()) System.out.println(o);
        UIManager.getLookAndFeelDefaults().forEach((key, value) -> System.out.println(key));
      }
    }
    
この方法は、一々LookAndFeelを作成してフォントを変更するのが面倒なときには便利です。LookAndFeelを自作する場合は、以下などを参考にしてみてください。 また、フォントが気に入らないだけなら、Metalで使ってるフォントが格好悪いので、それを変更してやるだけでいいかもしれません*1
  • -
  • JComboBox#setFont(...)で使用するフォントのサイズを変更しても、JComboBox自体のサイズが更新されない
    • JCombobox doesn't get resized according to font size change
      #spandel
      try{
      #spanend
        //UIManager.getSystemLookAndFeelClassName() で
        //NullPointerException が発生する場合のおまじない
        //UIManager.getInstalledLookAndFeels();
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
      #spandel
      }catch(Exception e) {
      #spanend
        e.printStackTrace();
      #spandel
      }
      #spanend
      #spanadd
      combo.setFont(font);
      #spanend
      #spanadd
      // 以下回避方法
      #spanend
      #spanadd
      combo.setPrototypeDisplayValue(null); // null:default?
      #spanend
      #spanadd
      // or combo.firePropertyChange("prototypeDisplayValue", 0, 1);
      #spanend
      

参考リンク

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

コメント

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

参考リンク

コメント