コンポーネントの表示テキスト、マルチフォントにできますか?
コンポーネントの多くは、コンポーネント上にテキストを表示しています。JLabel、JButton、JCheckBoxなど、みんなそうです。この表示テキストは、フォントや色などを変更することができます。では、「テキストをマルチフォントで表示させたい」という場合、どうすればよいでしょうか?
答えは、実はとても単純です。HTMLで表示テキストを作成し、設定すれば良いのです。Swingのコンポーネントは、HTMLをレンダリングして表示させることができます。これを利用すれば、思った以上に凝ったテキスト表示を行わせることができます。
例えば、先ほどのSampleAppのコンストラクタを次のように変更してみましょう。ボタンに黒と赤でテキストが表示されるはずです。
public SampleApp(){ this.setSize(new Dimension(200,200)); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); BoxLayout boxlayout = new BoxLayout(this.getContentPane(), BoxLayout.Y_AXIS); this.setLayout(boxlayout); for(int i = 0;i < 3;i++){ JButton btn = new JButton( "<html><b>Button<span style=\"color:#FF0000;\">" + i + "</span></b></html>"); btn.setFont(new Font("Serif",Font.PLAIN,18)); this.add(btn); } }

表示テキストに"<html>~テキスト~</html>"というようにして開始部分と終了部分に<html>、</html>をつけておけば、そのテキストをHTMLのコードとして認識します。
これを利用すれば、例えばボタンに複数行のテキストを表示させたりといったことも簡単に行うことができます。覚えておいて損はないテクニックです。
ルックアンドフィール、変えられますか?
Swingのコンポーネントの特徴として、「ルックアンドフィールが変更できる」という点が挙げられるでしょう。標準でいくつかのルックアンドフィールを用意しており、簡単な操作でコンポーネントの表示を変更することが可能です。――では、どうやって? 案外、実際にやってみたことない人、多いんじゃないでしょうか。
せっかくルックアンドフィールを操作できるのですから、そのやり方ぐらいは知っておきたいものです。では、いくつかのコンポーネントを配置した簡単なサンプルを作成してみましょう。
package jp.codezine; import java.awt.*; import java.awt.event.*; import java.util.*; import javax.swing.*; public class SampleApp extends JFrame implements ActionListener { private static final long serialVersionUID = 1L; private LaFComboBox combo; public SampleApp(){ this.setSize(new Dimension(200,150)); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); GridLayout layout = new GridLayout(4,1); layout.setHgap(5); layout.setVgap(5); this.setLayout(layout); createComponent(); } public void createComponent(){ JCheckBox check = new JCheckBox("checkbox"); this.add(check); JRadioButton radio = new JRadioButton("radio"); this.add(radio); combo = new LaFComboBox(); combo.addActionListener(this); this.add(combo); JButton btn = new JButton("button"); this.add(btn); } public void changeLookAndFeel(){ String s = combo.getSelectedLaF(); try { UIManager.setLookAndFeel(s); SwingUtilities.updateComponentTreeUI(this); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (UnsupportedLookAndFeelException e) { e.printStackTrace(); } } public void actionPerformed(ActionEvent ev){ this.changeLookAndFeel(); } public static void main(String[] args) { new SampleApp().setVisible(true); } } class LaFComboBox extends JComboBox { private static final long serialVersionUID = 1L; private Map<String,String> map; public LaFComboBox(){ UIManager.LookAndFeelInfo[] LaF = UIManager.getInstalledLookAndFeels(); map = new HashMap<String,String>(); for(UIManager.LookAndFeelInfo lf:LaF){ this.addItem(lf.getName()); map.put(lf.getName(),lf.getClassName()); } } public String getSelectedLaF(){ String s = (String)this.getSelectedItem(); return map.get(s); } }




ここでは、チェックボックス、ラジオボタン、コンボボックス、プッシュボタンといったコンポーネントを配置したウインドウを表示させています。コンボボックスからルックアンドフィール名を選択すると、ウインドウのルックアンドフィールが変更されます。コンボボックスには、利用可能なルックアンドフィール名が表示されているはずです。
ルックアンドフィール操作の仕組み
ここでは、ルックアンドフィールを表示したコンポーネントとして、JComboBoxを継承した「LaFComboBox」というクラスを用意しました。ここでルックアンドフィール名を表示したコンボボックスを作成しています。また、ルックアンドフィール名とそのクラス名をHashMapに保管し、それを利用して選択したルックアンドフィールのクラス名を取得するためのメソッドも用意しておきました。
ルックアンドフィールは、文字通りLookAndFeelというクラスとして用意されています。また、ルックアンドフィールに関する情報を管理するものとして、UIManager.LookAndFeelInfoというクラスも用意されています。このクラスを利用して、ルックアンドフィール名やLookAndFeelクラス名などを取得することができます。
LaFComboBoxのコンストラクタでは、次のようにしてルックアンドフィールに関する情報を取得しています。
UIManager.LookAndFeelInfo[] LaF = UIManager.getInstalledLookAndFeels();
UIManagerは、文字通りユーザーインターフェイスに関する各種情報を提供する機能を持つクラスです。getInstalledLookAndFeelsは、現在利用可能なルックアンドフィールに関する情報を得るためのメソッドで、UIManager.LookAndFeelInfo配列としてすべてのルックアンドフィールに関する情報を返します。
このUIManager.LookAndFeelInfoでは、getNameやgetClassNameメソッドにより、ルックアンドフィール名やクラス名を得ることができます。ここでは、あらかじめHashMapを用意しておき、そこにgetName値をキーにしてgetClassName値を保存しておきました。こうすることで、コンボボックスで選択した名前のキーの値を調べればクラス名が分かるようにしておいたわけです。
Swingでは、LookAndFeelクラスを直接利用してルックアンドフィールを変更することもできますし、クラス名を使って指定することも可能です。一般に、扱いやすいクラス名のString値を用意して操作することが多いでしょう。ここでもそうしています。ActionListenerで実行しているactionPerformedを見ると、getSelectedLaFでクラス名を取り出し、それを使ってルックアンドフィールを変更しています。
UIManager.setLookAndFeel(s);
引数にStringを指定するsetLookAndFeelメソッドは、ClassNotFoundException、 InstantiationException、 IllegalAccessException、 UnsupportedLookAndFeelExceptionとさまざまな例外を発生させる場合があるので注意が必要です。
これでルックアンドフィールは設定されましたが、この状態ではまだ各コンポーネントのルックアンドフィールは変更されません。このsetLookAndFeelで設定されるのは「デフォルトのルックアンドフィール」です。すなわち、これ以後コンポーネントを新たに作成すると、指定したルックアンドフィールで作成される、ということなのです。
コンポーネント類は、それまで設定されていたルックアンドフィールを使って既に表示が作成済みです。従って、作成したコンポーネントのルックアンドフィールを新たに設定したものに更新しなければいけません。
SwingUtilities.updateComponentTreeUI(this);
これが、その作業を行っているところです。コンポーネントは、大元となるコンテナ(通常はJFrame)内にツリー構造で組み込まれています。そのツリー構造に従って、組み込まれているコンポーネントのルックアンドフィールをすべて更新していきます。引数にJFrameを渡せば、そのJFrame内に組み込まれているコンポーネント類すべてが現在のルックアンドフィールに変わるわけです。
