2014年2月12日 星期三

Java Theme

Java Swing具有豐富多樣的外觀,其外觀可由Pluggable Look and Feel設定,此外,Java Swing支援主題(Theme),為Java Swing一個有趣的功能。在JDK 1.4(含)之前,若使用Metal Look and Feel,所呈現的主題樣式稱為Steel,較為灰暗。JDK 5.0新增Metal Look and Feel的主題樣式,稱為Ocean,較Steel明亮且有層次感,如下圖所示: 
Steel Theme
Ocean Theme

Java主題僅能搭配Metal Look and Feel使用,並不支援其它的Look and Feel。Steel與Ocean主題樣式的類別分別為: 

  • Steel:javax.swing.plaf.metal.DefaultMetalTheme 
  • Ocean:javax.swing.plaf.metal.OceanTheme 

OceanTheme類別繼承自DefaultMetalTheme類別,而DefaultMetalTheme類別則繼承自MetalTheme抽象類別。

欲設定主題樣式,需使用MetalLookAndFeel類別的setCurrentTheme()方法,其中參數theme為設定的主題樣式,為MetalTheme型別,可為DefaultMetalThemeOceanTheme類別。 

待執行setCurrentTheme()方法之後,需執行UIManager類別的setLookAndFeel()方法設定Metal Look and Feel及以SwingUtilities類別的updateComponentTreeUI()方法更新,例如:


// 設定為Metal Look and Feel之Ocean主題 
MetalLookAndFeel.setCurrentTheme(new OceanTheme()); 

try { 
  // 設定Metal Look and Feel 
  UIManager.setLookAndFeel(new MetalLookAndFeel()); 
  // 變更Look and Feel 
  SwingUtilities.updateComponentTreeUI(this); 

catch (Exception e) { 
  ... 
}


配合Window Decoration Style與Theme主題,可使用UIManager類別將Metal Look and Feel中的字形由粗體改為標準字型,如此介面將更加簡潔美觀,其屬性值為swing.boldMetal,例如:


UIManager.put("swing.boldMetal", Boolean.FALSE);


亦可設定Java直譯器的屬性值,此屬性值為swing.boldMetal,其語法如下: 

    java -Dswing.boldMetal=[true | false] [Java類別名稱] 

例如設定字形為標準字型: 

    java -Dswing.boldMetal=false ThemeDemo 

除了以MetalLookAndFeel類別的setCurrentTheme()方法設定主題樣式之外,亦可設定Java直譯器的屬性值,此屬性值為swing.metalTheme,其語法如下: 

    java -Dswing.metalTheme=[ocean | steel] [Java類別名稱] 

例如設定Steel主題: 

    java -Dswing.metalTheme=steel ThemeDemo 

除了使用DefaultMetalTheme與OceanTheme類別設定主題樣式之外,亦可自行開發。開發主題的類別需如同OceanTheme類別繼承DefaultMetalTheme類別,亦可如DefaultMetalTheme類別直接繼承MetalTheme抽象類別,而自訂類別需改寫DefaultMetalTheme類別或MetalTheme抽象類別的方法。

其次由於開發主題的類別,事實上是在改變Java Swing物件的顏色及字型,因此亦需自行調配物件的顏色與字型。依據Java Look and Feel Design Guidelines,Java將Pluggable Look and Feel主題的顏色分為以下八類,其中Primary顏色為作用中 (Active) 視窗或物件被選取時之顏色,Secondary顏色為非作用中 (Inactive) 視窗或物件的顏色,因此Secondary較Primary灰暗。此外為了產生3D效果,並分別將Primary與Secondary顏色細分為Primary 1、Primary 2與Primary 3及Secondary 1、Secondary 2與Secondary 3,顏色依序由深而淺: 

  • Primary 1:第一主要顏色,為有效視窗的邊框或系統文字如標籤等之顏色。 
  • Primary 2:第二主要顏色,為捲軸的捲軸方塊、進度功能列的已執行進度部份及被選取物件如選單或選單項目等之顏色。 
  • Primary 3:第三主要顏色,為有效視窗的標題列顏色或文字編輯物件中被選取文字的背景顏色。 
  • Secondary 1:第一次要顏色,為3D效果之物件如按鈕的邊框顏色。 
  • Secondary 2:第二次要顏色,為無效視窗的邊框顏色、按鈕按下時的顏色或非作用中 (Disable) 的按鈕與文字欄位之邊框顏色。 
  • Secondary 3:第三次要顏色,為無效視窗的標題列顏色或不可編輯 (Noneditable) 之文字欄位的背景顏色。 
  • Black:文字顏色。 
  • White:文字編輯物件如文字欄位的白色部份。 

DefaultMetalTheme類別(Steel主題)與上述顏色有關的方法如下: 

  • getPrimary1():取得Primary 1顏色,RGB分別為(102, 102, 153)。 
  • getPrimary2():取得Primary 2顏色,RGB分別為(153, 153, 204)。 
  • getPrimary3():取得Primary 3顏色,RGB分別為(204, 204, 255)。 
  • getSecondary1():取得Secondary 1顏色,RGB分別為(102, 102, 102)。 
  • getSecondary2():取得Secondary 2顏色,RGB分別為(153, 153, 153)。 
  • getSecondary3():取得Secondary 3顏色,RGB分別為(204, 204, 204)。 

上述方法均回傳javax.swing.plaf.ColorUIResource物件,ColorUIResource類別繼承java.awt.Color類別,事實上與Color類別一樣為處理顏色之類別,專為處理Pluggable Look and Feel主題顏色之調配。此類別只有建構函式,方法繼承自Color類別。 

ColorUIResource類別之建構函式為: 

    public ColorUIResource(Color c) 
    public ColorUIResource(float r, float g, float b) 
    public ColorUIResource(int rgb) 
    public ColorUIResource(int r, int g, int b) 

其中參數: 

  • c:設定上述Primary與Secondary主題顏色。 
  • r:為RGB紅色部份。 
  • g:為RGB綠色部份。 
  • b:為RGB藍色部份。 
  • rgb:為RGB之組合。 
例如:


// 設定Primary主題顏色 
private final ColorUIResource primary1 = 
  new ColorUIResource(100, 150, 150); 
... 

// 取得Primary主題顏色 
protected ColorUIResource getPrimary1() { 
  return primary1; 
}


請參考以下範例,自訂主題就是繼承DefaultMetalTheme類別並改變Java Swing物件的顏色及字型,介紹如何處理Pluggable Look and Feel主題顏色之調配與如何以繼承DefaultMetalTheme類別的方式自訂Theme主題之類別,除了原有Steel與Ocean主題樣式之外,並自訂Aqua、Green、Ruby、Sandstone及Contrast等樣式,其類別分別為AquaTheme、GreenTheme、RubyTheme、SandstoneTheme及ContrastTheme。 

以Aqua樣式為例,其繼承DefaultMetalTheme類別的方式為:


import javax.swing.*;
import javax.swing.plaf.*;
import javax.swing.plaf.metal.*;

public class AquaTheme extends DefaultMetalTheme {
  // 設定Primary主題顏色
  private final ColorUIResource primary1 =
    new ColorUIResource(100, 150, 150);
  private final ColorUIResource primary2 = 
    new ColorUIResource(130, 190, 190);
  private final ColorUIResource primary3 = 
    new ColorUIResource(150, 230, 230);

  // 設定Secondary主題顏色
  private final ColorUIResource secondary1 = 
    new ColorUIResource(110, 110, 110);
  private final ColorUIResource secondary2 = 
    new ColorUIResource(160, 160, 160);
  private final ColorUIResource secondary3 = 
    new ColorUIResource(220, 245, 245);

  // 取得Primary主題顏色
  protected ColorUIResource getPrimary1() { return primary1; }
  protected ColorUIResource getPrimary2() { return primary2; }
  protected ColorUIResource getPrimary3() { return primary3; }

  // 取得Secondary主題顏色
  protected ColorUIResource getSecondary1() { return secondary1; }
  protected ColorUIResource getSecondary2() { return secondary2; }
  protected ColorUIResource getSecondary3() { return secondary3; }
}


欲設定主題樣式,同樣需使用MetalLookAndFeel類別之setCurrentTheme()方法設定:


MetalLookAndFeel.setCurrentTheme(new AquaTheme());


【執行結果】 
其次以Contrast樣式為例,模擬對比之白底黑字,並以此改變文字、選單、選單項目及選單快速鍵等之顏色,此外程式並改寫MetalTheme抽象類別的addCustomEntriesToTable()方法,在此方法中將以下屬性值設定為白色或黑色,造成對比的效果: 

  • TextArea.border:文字區域的邊框顏色。 
  • TextField.border:文字欄位的邊框顏色。 
  • TextPane.font:文字面板的文字顏色。 
  • ToolTip.border:Tool Tips提示說明的邊框顏色。

例如


public void addCustomEntriesToTable(UIDefaults table) {
  Border blackLineBorder = new BorderUIResource(
    new LineBorder( getBlack() ));
  Border whiteLineBorder = new BorderUIResource(
    new LineBorder( getWhite() ));
  
  Object textBorder = new BorderUIResource(
    new CompoundBorder(blackLineBorder, 
    new BasicBorders.MarginBorder()));

  table.put("TextArea.border", textBorder);
  table.put("TextField.border", textBorder);
  table.put("TextPane.font", textBorder);
  table.put("ToolTip.border", blackLineBorder);
}


【執行結果】 
除了顏色之外,亦可改變Java Swing物件的字型。依據Java Look and Feel Design Guidelines,Java將Pluggable Look and Feel主題之字型分為以下四類: 

  • Control:為標籤、按鈕、核取方塊、選單、選單項目及視窗標題之字型,預設為12點Dialog粗體(Bold)字型,若以UIManager類別將屬性值swing.boldMetal設定為Boolean.FALSE,則其字型為12點Dialog標準(Plain)字型。 
  • Small:為選單快速鍵之字型,預設為10點Dialog標準字型。 
  • System:為樹(Tree)物件及Tool Tips提示說明之字型,預設為12點Dialog標準字型。 
  • User:為文字編輯物件及表格之字型,預設為12點Dialog標準字型。 

DefaultMetalTheme類別(Steel主題)與上述字型有關之方法有: 

  • getControlTextFont():取得Control字型,預設為12點Dialog粗體字型。 
  • getMenuTextFont():取得選單及選單項目之字型,預設為12點Dialog粗體字型。
  • getSubTextFont():取得Small字型,預設為10點Dialog標準字型。 
  • getSystemTextFont():取得System字型,預設為12點Dialog標準字型。
  • getUserTextFont():取得User字型,預設為12點Dialog標準字型。 
  • getWindowTitleFont():取得視窗標題之字型,預設為12點Dialog粗體字型。 

上述方法均回傳javax.swing.plaf.FontUIResource物件,FontUIResource類別繼承java.awt.Font類別,事實上與Font類別一樣為處理字型之類別,專為處理Pluggable Look and Feel主題字型之調配。此類別只有建構函式,方法繼承自Font類別。 

FontUIResource類別之建構函式為: 

    public FontUIResource(Font font) 
    public FontUIResource(String name, int style, int size) 

其中參數: 

  • font:設定前述之字型,為java.awt.Font型別。 
  • name:為字型名稱,可為Dialog、DialogInput、Monospaced、Serif或SansSerif等名稱。 
  • style:為字型樣式。 
  • size:為字型大小。 

例如:


// 設定Control字型為12點Dialog粗體字型
private final FontUIResource controlFont =
  new FontUIResource("Dialog", Font.BOLD, 12);

...

// 取得Control字型
getControlTextFont() { return controlFont; }


請參考以下範例,介紹如何處理Pluggable Look and Feel主題字型之調配。

範例自訂Low Vision及Presentation等樣式,以Low Vision樣式為例,其繼承DefaultMetalTheme類別的方式為:


import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.plaf.*;
import javax.swing.plaf.metal.*;

public class LowVisionTheme extends ContrastTheme {
  // 設定字型
  private final FontUIResource controlFont = 
    new FontUIResource("Dialog", Font.BOLD, 24);
  private final FontUIResource smallFont = 
    new FontUIResource("Dialog", Font.PLAIN, 20);
  private final FontUIResource systemFont = 
    new FontUIResource("Dialog", Font.PLAIN, 24);
  private final FontUIResource userFont = 
    new FontUIResource("SansSerif", Font.PLAIN, 24);
  private final FontUIResource windowTitleFont = 
    new FontUIResource("Dialog", Font.BOLD, 24);

  // 取得字型
  getControlTextFont() { return controlFont;}
  getMenuTextFont() { return controlFont;}
  getSubTextFont() { return smallFont;}
  getSystemTextFont() { return systemFont;}
  getUserTextFont() { return userFont;}
  getWindowTitleFont() {
    return windowTitleFont;
  }

  public void addCustomEntriesToTable(UIDefaults table) {
    super.addCustomEntriesToTable(table);
    
    final int internalFrameIconSize = 30;
    table.put("InternalFrame.closeIcon", 
      MetalIconFactory.getInternalFrameCloseIcon(
      internalFrameIconSize));
    table.put("InternalFrame.maximizeIcon", 
      MetalIconFactory.getInternalFrameMaximizeIcon(
      internalFrameIconSize));
    table.put("InternalFrame.iconifyIcon", 
      MetalIconFactory.getInternalFrameMinimizeIcon(
      internalFrameIconSize));
    table.put("InternalFrame.minimizeIcon", 
      MetalIconFactory.getInternalFrameAltMaximizeIcon(
      internalFrameIconSize));
    
    Border blackLineBorder = 
      new BorderUIResource( new MatteBorder( 2,2,2,2, Color.black) );
    Border textBorder = blackLineBorder;
    
    table.put("TextArea.border", textBorder);
    table.put("TextField.border", textBorder);
    table.put("TextPane.font", textBorder);
    table.put("ToolTip.border", blackLineBorder);
    table.put("ScrollPane.border", blackLineBorder);
    table.put("ScrollBar.width", new Integer(25));
  }
}


欲設定主題樣式,同樣需使用MetalLookAndFeel類別之setCurrentTheme()方法設定:


MetalLookAndFeel.setCurrentTheme(new LowVisionTheme());


【執行結果】 
【參考資料】 

[1] Java Platform, Standard Edition 7 API Specification. 
[2] 黃嘉輝,深入研究Java Swing (第二版)。 

© Chia-Hui Huang

沒有留言:

張貼留言