2015年4月18日 星期六

JavaFX Spinner

2015年03月03日Oracle推出JavaFX 8 Update 40,新增Spinner物件,Spinner原義為紡紗機,此處是指微調工具,其類別為javafx.scene.control.Spinner,類似於ListViewComboBox類別,均用以顯示一個以上的項目。

Spinner類別由箭頭與編輯物件 (Editor) 兩部份所組成,下圖為JavaFX之Spinner樣式:

JavaFX的Spinner支援int整數、double浮點數與自定字串清單,與Java Swing的JSpinner相比,Java Swing支援預設 (Default)、日期 (Date)、清單 (List)與數字 (Number)等格式,較JavaFX多了日期格式,下圖為Java Swing之JSpinner的日期樣式:
不過JavaFX的Spinner可設定箭頭位置與方向,分別由以下選項設定,若未指定,則為預設的右側垂直樣式:
  • Spinner.STYLE_CLASS_ARROWS_ON_RIGHT_HORIZONTAL:右側水平。
  • Spinner.STYLE_CLASS_ARROWS_ON_LEFT_VERTICAL:左側垂直。
  • Spinner.STYLE_CLASS_ARROWS_ON_LEFT_HORIZONTAL:左側水平。
  • Spinner.STYLE_CLASS_SPLIT_ARROWS_VERTICAL:分裂垂直。
  • Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL:分裂水平。
以下範例示範Spinner類別的各種箭頭位置與方向之樣式:
String[] styles = {
  "",                                             // 預設右側垂直
  Spinner.STYLE_CLASS_ARROWS_ON_RIGHT_HORIZONTAL, // 右側水平
  Spinner.STYLE_CLASS_ARROWS_ON_LEFT_VERTICAL,    // 左側垂直
  Spinner.STYLE_CLASS_ARROWS_ON_LEFT_HORIZONTAL,  // 左側水平
  Spinner.STYLE_CLASS_SPLIT_ARROWS_VERTICAL,      // 分裂垂直
  Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL     // 分裂水平
};

Spinner[] spinner = new Spinner[styles.length];

for (int i = 0; i < styles.length; i++) {
  spinner[i] = new Spinner(0, 100, 10);      // 最小值, 最大值, 預設值
  spinner[i].getStyleClass().add(styles[i]); // 設定箭頭位置與方向
  spinner[i].setPrefWidth(80);
}
...
【執行結果】
除了以上述Spinner的建構函式設定之外,亦可以使用SpinnerValueFactory設定Spinner的Model,分別如下:
  • SpinnerValueFactory.IntegerSpinnerValueFactory:Integer整數。
  • SpinnerValueFactory.DoubleSpinnerValueFactory:Double浮點數。
  • SpinnerValueFactory.ListSpinnerValueFactory:List清單。
以下範例示範以SpinnerValueFactory.DoubleSpinnerValueFactory設定Double浮點數的Spinner Model:
Spinner[] spinner = new Spinner[styles.length];

for (int i = 0; i < styles.length; i++) {
  // 最小值, 最大值, 預設值, 遞增減值
  SpinnerValueFactory svf = new 
    SpinnerValueFactory.DoubleSpinnerValueFactory(0.0, 10.0, 1.2, 0.1); 
  Spinner sp = new Spinner();
  sp.setValueFactory(svf);
  sp.getStyleClass().add(styles[i]);
  sp.setPrefWidth(80);
  spinner[i] = sp;
}
...
【執行結果】
比較特殊的是List清單,一般Spinner物件都用在選擇數字或日期,但JavaFX加入List清單功能,因此可自定字串清單,以下範例示範以SpinnerValueFactory.ListSpinnerValueFactory設定List清單的Spinner Model:
Spinner[] spinner = new Spinner[styles.length];

for (int i = 0; i < styles.length; i++) {
  ObservableList<String> months = 
    FXCollections.observableArrayList(
      "January", "February", "March", "April",
      "May", "June", "July", "August",
      "September", "October", "November", "December"
    );

  SpinnerValueFactory svf = new 
    SpinnerValueFactory.ListSpinnerValueFactory<>(months);
  Spinner sp = new Spinner();
  sp.setValueFactory(svf);
  sp.getStyleClass().add(styles[i]);
  sp.setPrefWidth(100);
  spinner[i] = sp;
}
...
【執行結果】
更進一步,可搭配CurrencyStringConverter設定貨幣格式,並以setStyle()方法設定Spinner的字型樣式:
TextFormatter<Number> formatter = 
  new TextFormatter<>(new CurrencyStringConverter());
formatter.setValue(50000);

Spinner spinner = new Spinner();
spinner.setPrefWidth(150);
spinner.setEditable(true);
spinner.getEditor().setTextFormatter(formatter);
spinner.getEditor().setStyle(
  "-fx-font: 10pt 'verdana'; 
   -fx-text-fill: black; 
   -fx-alignment: CENTER_RIGHT;"
);    
...
【執行結果】
以下範例更進一步以CurrencyStringConverter設定系統預設、美金 (Locale.US)、日幣 (Locale.JAPAN) 等貨幣格式,並以PercentageStringConverter設定百分比格式:
// 系統預設貨幣格式
TextFormatter<Number> formatter1 = 
  new TextFormatter<>(new CurrencyStringConverter());
formatter1.setValue(50000);

Spinner spinner1 = new Spinner();
spinner1.setPrefWidth(150);
spinner1.setEditable(true);
spinner1.getEditor().setTextFormatter(formatter1);
spinner1.getEditor().setStyle(
  "-fx-font: 10pt 'verdana'; 
   -fx-text-fill: black; 
   -fx-alignment: CENTER_RIGHT;"
);  

// 美金貨幣格式
TextFormatter<Number> formatter2 =  
  new TextFormatter<>(new CurrencyStringConverter(Locale.US));
formatter2.setValue(50000);

Spinner spinner2 = new Spinner();
spinner2.setPrefWidth(150);
spinner2.setEditable(true);
spinner2.getEditor().setTextFormatter(formatter2);
spinner2.getEditor().setStyle(
  "-fx-font: 10pt 'verdana'; 
   -fx-text-fill: black; 
   -fx-alignment: CENTER_RIGHT;"
);  

// 日幣貨幣格式
TextFormatter<Number> formatter3 =  
  new TextFormatter<>(new CurrencyStringConverter(Locale.JAPAN));
formatter3.setValue(50000);

Spinner spinner3 = new Spinner();
spinner3.setPrefWidth(150);
spinner3.setEditable(true);
spinner3.getEditor().setTextFormatter(formatter3);
spinner3.getEditor().setStyle(
  "-fx-font: 10pt 'verdana'; 
   -fx-text-fill: black; 
   -fx-alignment: CENTER_RIGHT;"
);  

// 百分比格式
TextFormatter<Number> formatter4 = 
  new TextFormatter<>(new PercentageStringConverter(););
formatter4.setValue(0.12);

Spinner spinner4 = new Spinner();
spinner4.setPrefWidth(150);
spinner4.setEditable(true);
spinner4.getEditor().setTextFormatter(formatter4);
spinner4.getEditor().setStyle(
  "-fx-font: 10pt 'verdana'; 
   -fx-text-fill: black; 
   -fx-alignment: CENTER_RIGHT;"
);  
...
【執行結果】
雖然Spinner物件不直接支援日期格式,但仍可以搭配SimpleDateFormat的方式設定各種日期格式,請參考以下範例:
try {
  Calendar calendar = Calendar.getInstance();

  // yyyy/MM/dd
  SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy/MM/dd");
  // 指定日期
  calendar.setTime(DateFormat.getDateInstance().parse("2015/5/10"));    

  Spinner spinner1 = new Spinner();
  spinner1.setPrefWidth(220);
  spinner1.setEditable(true);
  spinner1.getEditor().setText(sdf1.format(calendar.getTime()));
  spinner1.getEditor().setStyle(
    "-fx-font: 10pt 'verdana'; 
     -fx-text-fill: black; 
     -fx-alignment: CENTER_RIGHT;"
  );      

  // E yyyy/MM/dd
  SimpleDateFormat sdf2 = new SimpleDateFormat("E yyyy/MM/dd");
  // 指定日期
  calendar.setTime(DateFormat.getDateInstance().parse("2015/5/10"));    

  Spinner spinner2 = new Spinner();
  spinner2.setPrefWidth(220);
  spinner2.setEditable(true);
  spinner2.getEditor().setText(sdf2.format(calendar.getTime()));
  spinner2.getEditor().setStyle(
    "-fx-font: 10pt 'verdana'; 
     -fx-text-fill: black; 
     -fx-alignment: CENTER_RIGHT;"
  );        

  // yyyy/MM/dd HH:mm:ss
  SimpleDateFormat sdf3 = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");

  Spinner spinner3 = new Spinner();
  spinner3.setPrefWidth(220);
  spinner3.setEditable(true);
  // 系統目前日期
  spinner3.getEditor().setText(sdf3.format(new Date()));
  spinner3.getEditor().setStyle(
    "-fx-font: 10pt 'verdana'; 
     -fx-text-fill: black; 
     -fx-alignment: CENTER_RIGHT;"
  );      

  // EEE, MMM d, 'yy
  SimpleDateFormat sdf4 = new SimpleDateFormat("EEE, MMM d, ''yy");

  Spinner spinner4 = new Spinner();
  spinner4.setPrefWidth(220);
  spinner4.setEditable(true);
  // 系統目前日期
  spinner4.getEditor().setText(sdf4.format(new Date()));
  spinner4.getEditor().setStyle(
    "-fx-font: 10pt 'verdana'; 
     -fx-text-fill: black; 
     -fx-alignment: CENTER_RIGHT;"
  );         
  
  ...
} 
catch (Exception  e) {
  e.printStackTrace();
}
...
【執行結果】
【參考資料】

[1] Java Official Web Site:http://www.oracle.com/technetwork/java/index.html
[2] JavaFX:http://www.oracle.com/technetwork/java/javafx
[3] JavaFX 8.0 API Specification.
[4] Java Platform, Standard Edition 8 API Specification.

© Chia-Hui Huang

1 則留言:

  1. 好久沒來了…雖然jQuery Moblie比較流行,我還是比較喜歡JavaFX

    回覆刪除