分だけのカッコ良いアプリを作りたい,の巻
2002.05.09 新規

カッコ良いアプリ = 見た目!

というコトで

といった作業を行います。 基本は独自ルック&フィールの元締め的クラスを作り、その中で所属させる子分たち(JButton とか)を宣言するだけです。 なので難しい話は、あまりありません。
逆に、どういう見せかたをするか、実際にどんな感じで描画するか、といった点で悩ましい思いをさせられることでしょう。

例えば、下のような見栄えのアプリが作れます。 この例ではボタン等に陰影を付けて、丸みを帯びた立体的なコンポーネントを表現しています。

LHMelt のオプション設定を真似っこ
比較画像

このような立体化は、「〜 UI」クラスの paint() メソッドや paintBackground() メソッドなどで描画しています。 この部分が、どういう見せかたをするか、実際にどんな感じで描画するか となります。 その辺りは今回の範囲外なので、各自で存分に苦しんでください。

 

見栄えを良くしたいコンポーネントは、 元締めクラス(ここでは「 Musi_chanLookAndFeel 」とする)の中で独自路線に進むことを宣言(登録)します。
例えば JButton クラスの見栄えを変える場合、デフォルト UI テーブルに「Musi_chanButtonUI」といった感じで設定します。 そのあとで「Musi_chanButtonUI」クラスを作成し、paint() メソッドをオーバ・ライトすることで実際に見た目が変更されます。 同様に、JTextField クラスの場合であれば UI テーブルに「Musi_chanTextFieldUI」を設定し、 「Musi_chanTextFieldUI」クラスで paintBackground() メソッドを上書き実装すれば良いです。

なお、クラス作成の簡略化のために、「metal」もしくは「basic」LookAndFeel で定義されているクラス群を親クラスにしています。

オブジェクト指向 万歳、って感じ? な〜んて。

 

・・・といったところで力尽きたので、あとはサンプル・ソース等を見ながら四苦八苦してみてください。


「SampleFrame.java」のソースコード
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.plaf.metal.*;
import java.util.*;

/**
 * サンプル・プログラムです.
 * 
 * @author Musi_chan
 * (Musi_chan@cool.biglobe.ne.jp)
 * @version 2002/05/09 11:58
 */
public class SampleFrame extends JFrame implements ActionListener {
/******************************************************************************
  フィールド
******************************************************************************/
  /**
   * メイン・パネルのインスタンス変数です.
   */
  private JPanel routePanel;
  /**
   * メイン・メニューバーのインスタンス変数です.
   */
  private JMenuBar routeMenuBar;

/******************************************************************************
  コンストラクタ
******************************************************************************/
  /**
   * コンストラクタです.
   */
  public SampleFrame() {
    Musi_chanLookAndFeel myLaF;
    Musi_chanTheme myTheme;

    // 各種ウィンドウ設定
    setLocation(50,25);
    setSize(340,400);
    setResizable(true);
    setTitle("Sample program.");
    getContentPane().setLayout(new BorderLayout());
    //setIconImage(ICON.getImage());
    setBackground(SystemColor.menu);
    setForeground(SystemColor.menuText);
    setDefaultCloseOperation(EXIT_ON_CLOSE);

    // ルック&フィール設定
    // テーマの変更
    myLaF=new Musi_chanLookAndFeel();
    myTheme=new Musi_chanTheme();
    MetalLookAndFeel.setCurrentTheme(myTheme);
    try {
      // テーマの設定
      UIManager.setLookAndFeel(myLaF);
      myLaF.setCurrentTheme(myTheme);
    } catch (Exception e) {
    }

    // メニューバーの作成と配置
    setMenuBar();
    setJMenuBar(routeMenuBar);
    // メイン・パネルの設定と追加
    setRoutePanel();
    getContentPane().add(routePanel,BorderLayout.CENTER);

    // メイン・ウィンドウの表示
    setVisible(true);
  }

/******************************************************************************
  メソッド
******************************************************************************/

/******************************************************************************
  ビュー
******************************************************************************/
  /**
   * メニューバーの設定をするメソッドです.
   */
  private void setMenuBar() {
    // メニューバーのインスタンス生成
    routeMenuBar=new JMenuBar();

    // ファイル・メニューをメニューバーに追加
    routeMenuBar.add(setFileMenu());
  }

  /**
   * ファイル・メニューの設定をするメソッドです.
   * 
   * @return 設定済みメニュー
   */
  private JMenu setFileMenu() {
    // ファイル・メニュー保持用ローカル変数
    JMenu fileMenu;
    // 終了メニューアイテム保持用ローカル変数
    JMenuItem extMenuItem;

    // ファイル・メニューの初期化
    // メニューのインスタンス生成
    fileMenu=new JMenu("File");
    // ニーモニックの設定(Alt+Fでも可にする)
    fileMenu.setMnemonic('F');

    // 終了メニューアイテムの初期化など
    extMenuItem=new JMenuItem("eXit");
    extMenuItem.setMnemonic('X');
    extMenuItem.setActionCommand("window exit");
    extMenuItem.addActionListener(this);
    fileMenu.add(extMenuItem);

    return fileMenu;
  }

  /**
   * メイン・パネルの設定をするメソッドです.
   */
  private void setRoutePanel() {
    JPanel panel;

    // ルートパネルのインスタンス生成
    routePanel=new JPanel(new BorderLayout());

    panel=new JPanel(new GridLayout(12,1,4,4));
    panel.add(new JLabel("デフォルトディレクトリ"));
    panel.add(new JTextField("c:\\temp\\"));
    panel.add(new JCheckBox("デフォルトディレクトリを使用"));
    panel.add(new JCheckBox("ディレクトリ付き解凍",true));
    panel.add(new JCheckBox("即時解凍時にログを非表示"));
    panel.add(new JCheckBox("Viewer 起動時の状況表示の抑制"));
    panel.add(new JCheckBox("Quick 解凍を使用"));
    panel.add(Box.createVerticalStrut(8)); // 空欄
    panel.add(new JCheckBox("リスト表示に \'V\' 命令を使用"));
    panel.add(new JCheckBox("バッググラウンドモード"));
    panel.add(new JLabel("サブオプション"));
    panel.add(new JTextField(""));
    routePanel.add(panel,BorderLayout.CENTER);

    panel=new JPanel();
    panel.setLayout(new BoxLayout(panel,BoxLayout.Y_AXIS));
    panel.add(Box.createVerticalStrut(32)); // 空欄
    panel.add(new JButton("了解"));
    panel.add(Box.createVerticalStrut(16)); // 空欄
    panel.add(new JButton("取消"));
    routePanel.add(panel,BorderLayout.EAST);

    panel=new JPanel(new FlowLayout());
    panel.add(new JButton("DLL の設定 >>"));
    panel.add(Box.createHorizontalStrut(16)); // 空欄
    panel.add(new JButton("詳細設定 >>"));
    routePanel.add(panel,BorderLayout.SOUTH);
  }

/******************************************************************************
  コントローラ
******************************************************************************/
  /**
   * メインメソッドです.起動時に呼び出されます.
   * 
   * @param args コマンドライン引数
   */
  public static void main(String[] args) {
    // 自身のインスタンス生成(=アプリの開始)
    new SampleFrame();
  }

  /**
   * アクションイベント用メソッドです.
   * メニューが押されたときに呼び出されます.
   * 
   * @param ae アクションイベント
   */
  public void actionPerformed(ActionEvent ae) {
    // トークン保持用ローカル変数
    String token;
    // トークン分解用ローカル変数
    StringTokenizer st;

    // イベントに設定されたアクションコマンドをトークン分解
    st=new StringTokenizer(ae.getActionCommand()," ");
    token=st.nextToken();
    // 第1トークンの判定
    if(token.equalsIgnoreCase("window")) {
      // ウィンドウ関係の処理
      token=st.nextToken();
      // 第2トークンの判定
      if(token.equalsIgnoreCase("exit")) {
        System.exit(0);
      }
    }
  }
}


「Musi_chanLookAndFeel.java」のソースコード
import java.awt.*;
import javax.swing.*;
import javax.swing.plaf.metal.*;

/**
 * Original look&feel.
 * 
 * @author Musi_chan
 * (Musi_chan@cool.biglobe.ne.jp)
 * @version 2002/05/09 11:16
 */
public class Musi_chanLookAndFeel extends MetalLookAndFeel {
  public Musi_chanLookAndFeel() {
    // super();
  }

  public String getID() {
    return "Musi_chan";
  }

  public String getName() {
    return "Musi_chan";
  }

  public String getDescription() {
    return "Musi_chan's original Look&Feel";
  }

  public boolean isNativeLookAndFeel() {
    return false;
  }

  public boolean isSupportedLookAndFeel() {
    return true;
  }

  protected void initClassDefaults(UIDefaults table) {
    super.initClassDefaults(table);
    putDefault(table,"ButtonUI");
    putDefault(table,"TextFieldUI");
    putDefault(table,"MenuBarUI");
    putDefault(table,"MenuUI");
    putDefault(table,"CheckBoxUI");
    try {
      String className="Musi_chanCheckBoxIcon";
      table.put("CheckBox.icon",className);
    } catch(Exception e) {
      e.printStackTrace();
    }
  }

  protected void putDefault(UIDefaults table,String uiKey) {
    try {
      String className="Musi_chan"+uiKey;
      table.put(uiKey,className);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public UIDefaults getDefaults() {
    setCurrentTheme(new Musi_chanTheme());

    return super.getDefaults();
  }

  protected void initSystemColorDefaults(UIDefaults table) {
    super.initSystemColorDefaults(table);

    Color c;

    c=getTextHighlightColor();
    table.put("textHighlight"
      ,new Color(c.getRed(),c.getGreen(),c.getBlue(),128));
  }
}


「Musi_chanTheme.java」のソースコード
import java.awt.*;
import javax.swing.plaf.*;
import javax.swing.plaf.metal.*;

/**
 * Original look&feel (theme).
 * 
 * @author Musi_chan
 * (Musi_chan@cool.biglobe.ne.jp)
 * @version 2002/05/09 11:42
 */
public class Musi_chanTheme extends DefaultMetalTheme {
  // component colors
  private static Color compGradCol1=new Color(255,255,255,0);
  private static Color compGradCol2=new Color(255,255,255,128);
  private static Color compGradCol3=new Color(0,0,0,0);
  private static Color compGradCol4=new Color(0,0,0,96);
  // primary colors
  private ColorUIResource primary1;
  private ColorUIResource primary2;
  private ColorUIResource primary3;
  // secondary colors
  private ColorUIResource secondary1;
  private ColorUIResource secondary2;
  private ColorUIResource secondary3;
  // fonts
  protected FontUIResource controlFont;
  protected FontUIResource systemFont;
  protected FontUIResource userFont;
  protected FontUIResource menuFont;
  protected FontUIResource smallFont;


  public Musi_chanTheme() {
    this(12,12,12,12);
  }

  public Musi_chanTheme(int fontSize) {
    this(fontSize,fontSize,fontSize,fontSize);
  }

  public Musi_chanTheme(int[] fontSize) throws ArrayIndexOutOfBoundsException {
    this(fontSize[0],fontSize[1],fontSize[2],fontSize[3]);
  }

  public Musi_chanTheme(int ctrlFontSize,int sysFontSize
    ,int userFontSize,int menuFontSize) {

    super();

    controlFont=new FontUIResource("Dialog",Font.PLAIN,ctrlFontSize);
    systemFont=new FontUIResource("Dialog",Font.PLAIN,sysFontSize);
    userFont=new FontUIResource("Dialog",Font.PLAIN,userFontSize);
    menuFont=new FontUIResource("Dialog",Font.PLAIN,menuFontSize);
    smallFont=new FontUIResource("Dialog",Font.PLAIN,(int)(sysFontSize*0.8)+1);

    primary1=new ColorUIResource(120,140,170);
    primary2=new ColorUIResource(170,190,220);
    primary3=new ColorUIResource(220,240,250);
    secondary1=new ColorUIResource(120,120,170);
    secondary2=new ColorUIResource(170,170,220);
    secondary3=new ColorUIResource(220,220,250);
  }


  public String getName() {
    return "Musi_chanTheme";
  }

  public void setFontSize(int[] size) {
    setControlTextFont(size[0]);
    setSystemTextFont(size[1]);
    setUserTextFont(size[2]);
    setMenuTextFont(size[3]);
  }

  public void setControlTextFont(int size) {
    controlFont=new FontUIResource("Dialog",Font.PLAIN,size);
  }

  public FontUIResource getControlTextFont() {
    return controlFont;
  }

  public void setSystemTextFont(int size) {
    systemFont=new FontUIResource("Dialog",Font.PLAIN,size);
    smallFont=new FontUIResource("Dialog",Font.PLAIN,(int)(size*0.8)+1);
  }

  public FontUIResource getSystemTextFont() {
    return systemFont;
  }

  public FontUIResource getWindowTitleFont() {
    return systemFont;
  }

  public FontUIResource getSubTextFont() {
    return smallFont;
  }

  public void setUserTextFont(int size) {
    userFont=new FontUIResource("Dialog",Font.PLAIN,size);
  }

  public FontUIResource getUserTextFont() {
    return userFont;
  }

  public void setMenuTextFont(int size) {
    menuFont=new FontUIResource("Dialog",Font.PLAIN,size);
  }

  public FontUIResource getMenuTextFont() {
    return menuFont;
  }

  protected ColorUIResource getPrimary1() {
    return primary1;
  }

  protected ColorUIResource getPrimary2() {
    return primary2;
  }

  protected ColorUIResource getPrimary3() {
    return primary3;
  }

  protected ColorUIResource getSecondary1() {
    return secondary1;
  }

  protected ColorUIResource getSecondary2() {
    return secondary2;
  }

  protected ColorUIResource getSecondary3() {
    return secondary3;
  }

  protected static Color getCompGradColor1() {
    return compGradCol1;
  }

  protected static void setCompGradColor1(Color c) {
    compGradCol1=c;
  }

  protected static Color getCompGradColor2() {
    return compGradCol2;
  }

  protected static void setCompGradColor2(Color c) {
    compGradCol2=c;
  }

  protected static Color getCompGradColor3() {
    return compGradCol3;
  }

  protected static void setCompGradColor3(Color c) {
    compGradCol3=c;
  }

  protected static Color getCompGradColor4() {
    return compGradCol4;
  }

  protected static void setCompGradColor4(Color c) {
    compGradCol4=c;
  }
}

戻る