iT邦幫忙

2026 iThome 鐵人賽

DAY 30
0
Software Development

玩轉ABCL Lisp!用奇怪偏門的方式學習JavaFX系列 第 30 篇

lesson 21 (S3): MessageBox 之外的更多 Dialog 預設類型

  • 分享至 

  • xImage
  •  

TL;DR

JavaFX 除了用來顯示訊息的 Alert,也提供讓使用者選擇項目的 ChoiceDialog,以及輸入文字的 TextInputDialog。使用 showAndWait() 後,記得檢查回傳的 Optional,確認使用者是否有完成操作。

Alert

在Hello Button & Action使用了#'make-messagebox建立一個顯示訊息的對話框:

(defun make-messagebox (msg)
  (new +Alert+ +AlertType.INFORMATION+
       msg
       (jarray-from-list
        `(,+ButtonType.OK+))))

但因為當時並不在意使用者按下了什麼按鈕,或是直接關閉對話框,所以直接使用show()顯示對話框:

(prog ((alert (make-messagebox "Clicked Button")))
   (#"show" alert))

這篇先來看看如何得知使用者按下了哪個按鈕。為了方便嘗試,直接使用發揮ABCL威力建立ABCL-EVAL場景,並切換到:abcl-javafx Package。

(in-package :abcl-javafx)

https://ithelp.ithome.com.tw/upload/images/20261013/20112470k3BlMLGgXA.png

使用 showAndWait() 取得回應

原本我們是用show():

(#"show" (make-messagebox "hello"))

但是不管操作什麼回傳的結果都是NIL。

https://ithelp.ithome.com.tw/upload/images/20261013/20112470sNz9LGAXyj.png

換成showAndWait():

(#"showAndWait" (make-messagebox "hello"))

現在會根據使用者按下OK或直接關閉對話框,回傳不同結果:Optional中包含ButtonType.OK,或回傳Optional.empty。

https://ithelp.ithome.com.tw/upload/images/20261013/20112470LbGdFRc8W4.png

Alert建構子允許加入不同類型的按鈕:

(#"showAndWait" (new +Alert+
                     (jfield +AlertType+ "INFORMATION")
                     "嘗試不同的Alert"
                     (jarray-from-list `(,(jfield +ButtonType+ "OK")
                                          ,(jfield +ButtonType+ "CANCEL")
                                          ,(jfield +ButtonType+ "FINISH")
                                          ,(jfield +ButtonType+ "NEXT")
                                          ,(jfield +ButtonType+ "YES")
                                          ,(jfield +ButtonType+ "NO")
                                          ,(jfield +ButtonType+ "APPLY")
                                          ,(jfield +ButtonType+ "PREVIOUS")
                                          ,(jfield +ButtonType+ "CLOSE")))))

https://ithelp.ithome.com.tw/upload/images/20261013/201124704DtFfKvFIb.png
https://ithelp.ithome.com.tw/upload/images/20261013/20112470mimL3Nw6ot.png

Alert 類型與預設按鈕

Alert是javafx.scene.control.Dialog<ButtonType>的子類別。建立Alert時傳入Alert.AlertType,JavaFX會根據類型預先設定標題、標頭文字、圖示和適合的按鈕。官方API提供以下幾種類型:

類型 適合的用途 預設按鈕
INFORMATION 一般資訊或操作成功 OK
WARNING 可能造成問題的提醒 OK
ERROR 操作失敗或例外錯誤 OK
CONFIRMATION 要求使用者確認操作 OK、CANCEL
NONE 不指定預設的視覺類型 依建構方式而定

不過我不太確定這是因為在ABCL中使用的關係,還是有哪裡修改了風格;設定不同的AlertType時,外觀差異並不大。相較之下,從Java實作的CalcFX中,Alert風格就豐富許多。

https://ithelp.ithome.com.tw/upload/images/20261013/20112470ozGqTHImna.png

其他內建對話框

除了Alert(MessageBox)以外,JavaFX還提供選擇對話框(ChoiceDialog)和文字輸入對話框(TextInputDialog),分別用來讓使用者選擇項目或輸入文字。

ChoiceDialog

先來看看選擇對話框。要讓使用者從幾個選項中選一個,可以使用ChoiceDialog<T>。它的選項參數是Java的Collection,因此這裡先建立ArrayList再加入選項:

(defvar *color-options*
    (let* ((c (new "java.util.ArrayList")))
	    (#"add" c "紅色")
		(#"add" c "綠色")
		(#"add" c "藍色")
		c))

同樣要在:abcl-javafx裡評估。 (in-package :abcl-javafx)

然後建立ChoiceDialog,並提供*color-options*做為選項清單,以「綠色」做為預設選項:

(let* ((+ChoiceDialog+	"javafx.scene.control.ChoiceDialog")
	       (dialog (new +ChoiceDialog+ "綠色" *color-options*)))
	  (#"setTitle" dialog "選擇顏色")
	  (#"setHeaderText" dialog "請選擇一種顏色")
	  (#"setContentText" dialog "顏色:")
      (#"showAndWait" dialog))

和Alert一樣,回傳值是Optional類別,需要先判斷使用者是否真的選擇了值。改寫如下:

(let* ((+ChoiceDialog+	"javafx.scene.control.ChoiceDialog")
	       (dialog (new +ChoiceDialog+ "綠色" *color-options*)))
	  (#"setTitle" dialog "選擇顏色")
	  (#"setHeaderText" dialog "請選擇一種顏色")
	  (#"setContentText" dialog "顏色:")
-      (#"showAndWait" dialog))
+	  (let ((result (#"showAndWait" dialog)))
+				(when (#"isPresent" result)
+					(#"get" result))))

在ABCL中建立的ChoiceDialog外觀不太理想,因此這裡附上官方文件中的範例畫面:

TextInputDialog

不同於前兩者,Alert用按鈕提供選項;ChoiceDialog提供下拉式選單,文字輸入對話框則是由使用者自行輸入內容回覆。所以如果對話框的目的不是通知、也不是選項選擇,而是取得一段文字,使用TextInputDialog是一個簡單的方式:

;;(let ()

(defconstant +TextInputDialog+
	"javafx.scene.control.TextInputDialog")

(defun ask-name ()
	(let ((dialog (new +TextInputDialog+ "Anonymous")))
		(#"setTitle" dialog "輸入名稱")
		(#"setHeaderText" dialog "建立使用者")
		(#"setContentText" dialog "名稱:")
		(let ((result (#"showAndWait" dialog)))
			(when (#"isPresent" result)
				(#"get" result)))))

(ask-name)
;;)

註解掉的兩行(let ()、),是為了讓ABCL-EVAL將其視為整個評估形式(form),一次評估並保留最後形式的結果做為回傳值。
也可以一段一段的輸入到ABCL-EVAL去執行,結果也是會相同的。

https://ithelp.ithome.com.tw/upload/images/20261013/20112470iUxBAF0Ca0.png

以上介紹了JavaFX提供的三種常用對話框:通知或確認訊息用Alert,從清單選值用ChoiceDialog,取得文字輸入則用TextInputDialog。需要讀取使用者的選擇或輸入時,使用showAndWait()並檢查Optional是否有值;接著可以試著將其中一種對話框接到自己的 JavaFX 操作流程中。


上一篇
lesson 20 (S3): ASSNLC 的關係(Application、Stage、Scene、Node、Layout、Control)
下一篇
lesson 22(S4): 實現JAVA介面的另一種方式:jmake-proxy
系列文
玩轉ABCL Lisp!用奇怪偏門的方式學習JavaFX 共 33 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言