iT邦幫忙

2026 iThome 鐵人賽

0

系列資源:範例程式

本系列 Lesson 1~Lesson 16 的程式碼,可以在 GitHub 取得。

針對 Windows、Linux 平台,已編譯並建立可直接執行的檔案,可於 Release 頁面 取得。

  • lesson15-binary-linux.tar.gz
  • lesson15-binary-windows.zip
  • lesson16-binary-linux.tar.gz
  • lesson16-binary-windows.zip

其他 JAR 檔案是 ASDF 打包後的結果,可以參考將 ASDF 打包成 JAR了解如何載入並執行。不過,只有後面的 Lesson 正確調整了資源位置;最早的 Lesson 可能無法正確載入 CSS 和 ICON,建議直接使用倉庫中的原始碼。

本系列之後也預計發表於個人網站:https://www.lagagain.com/
請多關照~

後記

TL;DR

這篇後記回顧了系列的發想、寫作過程與完賽後對 JavaFX 的看法,也分享了 AI 如何協助寫作、又有哪些地方仍需自己查證與重寫。對我而言,參賽最大的收穫不只是學習 JavaFX,也包括透過持續輸出建立學習、寫作與時間管理的習慣;文末另補充幾則沒有納入主線的 JavaFX 和 ABCL 筆記。

賽前準備

這次直到最早的開賽日過後,我才開始構思系列內容(最早可於 8 月 1 日開賽,我則到 8 月 26 日才開始規劃)。相較之下,前幾年參賽時基本上都已有規劃,像是30天 Lua重拾筆記從當年 3 月開始構思;用Keycloak學習身份驗證與授權在 1、2 月就有了想法;這些那些你可能不知道我不知道的Web技術細節和與雲原生精靈共舞:APISIX使用者的兩年旅程則基本上與工作相關。但這次不同,主題幾乎完全出於個人喜好,更有種回到最初參加鐵人賽時,邊寫邊學習的感覺。

這次的發想來自 6~7 年前的筆記和 gist,也有一部分來自為什麼選擇 JavaFX提到的:我有點受夠了越來越多畫面看似華麗,用起來卻極度不成熟的 Electron 應用。

AI調研不可全信

學習主題的發想畢竟來自 6~7 年前的筆記,不一定真的適合自己,因此我也透過 AI 調查了幾個有興趣的候選項目。以下是 ChatGPT 提供的總結:

如果單純以 2026 年「新專案值得選擇」來看,我會大致排:

Qt / Avalonia > wxWidgets > GTK > JavaFX

但如果限定 Linux Desktop:

GTK / Qt > wxWidgets / Avalonia > JavaFX

而如果你是在做跨平台企業內部工具,我會特別推薦你把 Qt、Avalonia、wxWidgets 三個拿來深入比較;JavaFX 和 GTK 的適用情境相對更明確。

我也詢問了幾種介面描述語言的設計差異:

特性 QML FXML AXAML
所屬框架 Qt Quick JavaFX Avalonia UI
UI 宣告式語法 有 有(XML) 有(XAML)
可直接寫程式邏輯 可以 不行(純 XML) 有限度可以
內嵌 Script 語言 JavaScript 無 無原生通用 Script
事件處理 JS 函式、繫結 指向 Java Controller 方法 Event Handler、Command
複雜邏輯 QML + C++/Python 等 Java Controller C#
UI 與邏輯分離 可選擇分離 常見做法 常見做法

以我的經驗,使用 AI 查詢確實輕鬆很多,但不可全信。AI 生成的結果仍有可能不正確,例如 JavaFX 的 FXML 也可以寫 Script,提供了 <fx:script/> 標籤。我對 Avalonia UI 不熟(但有興趣),另一個 AI 卻告訴我,AXAML 沒有在介面描述語言中直接加入程式邏輯的設計,與上述是衝突的。

不只這次如此。我詢問 Grafana 設定問題,特別是 Infinity 和 UQL 的用法時,也經常得到無法直接使用的結果。自己閱讀文件和除錯的能力仍然不可或缺。

賽中撰稿

這次雖然是先有程式碼、後有文章,但每個階段的程式碼都有明確的學習目標。

完成一個學習目標後,除了已規劃的下一個目標,經常也會自然長出次要的分支目標,因此規劃內容並不太困難。

不過,真的要把內容寫成文章,經常又像是另一回事。AI 是個好工具,這次寫作也多少有 AI 輔助;依使用程度,大致可以分成三個層次:一、少量使用 AI,糾正錯字、協助總結,或多生成一些輔助圖片;二、提供大綱,由 AI 生成完整文章;三、只提供主題方向,由 AI 自行查找資料並生成完整文章。

AI 使用:糾正錯字,協助總結

以這次經驗來說,輕度使用 AI 的幫助很大!

錯字更正省去了大量心力檢查,甚至有一次的經驗是自己記錯程式碼作用,重新檢視後發現AI的觀點才是正確的。

生成的圖片可以很好看,儘管能夠感覺就是生成的(也僅有一張相對樸素的感覺沒那麼明顯),但因為並不是系列重點。

AI使用:提供大綱,生成完整文章。

先提供內容大綱,再由 AI 生成文章內容;大概有兩篇是這麼產生的。

但看似很輕鬆,有一篇生成了三次才是相對滿意的內容。並且內容上也幾乎有七成重新改過。

可能我的參賽目的有關,並沒有感受到輕鬆多少。

AI使用:提供主題方向,生成完整文章。

大概有四、五篇原本只提供主題方向,最多再附上程式碼範例,讓 AI 自行推論意圖、查找資料,再參照其他篇文章的風格生成內容。

但最終,這種做法產生的內容幾乎都被我重寫過。並不是生成的內容不好,後續調整時我也參考了其中一些內容;只是重寫之後,我才發現自己不喜歡原本的表達。原因之一,或許是它在邏輯描述、說明方式和內容順序上都與我的思路不合,讀起來像是在吞刺,反而讓我不舒服。

賽後感想

「如果連寫作都不願花時間,別人又為何要花時間閱讀?」

使用 AI 生成內容還有一個問題:只用簡單的提示詞產生的內容,容易充滿 AI 味。這種味道已經氾濫到令人反感。我也曾詢問一篇文章更深層的細節與意圖,提供內容的人卻完全答不上來,實在稱不上作者。TechNews 科技新報的一篇報導提到,AI 研究實驗室 Exa 的一位員工如此說明這個問題:「如果連寫作都不願花時間,別人又為何要花時間閱讀?」

費曼學習法:輸出是好的學習方式。但輸出是為了輸入的話,則不應該太依賴AI

這次參加 iT 鐵人賽,最大的目的之一是學習 JavaFX。因此,「如果是為了輸入而做輸出的話,不應該太依賴AI」。資料轉化為資訊的過程分成三個步驟:一、輸入;二、處理;三、輸出。我們可以透過 AI 產生輸出,也可以把 AI 產生的內容當作輸入;但學習中最重要的「處理」部分,AI 很難取代。百靈果 News在 09 月 10 日發布的 Podcast 中訪問了洪兆祥博士。洪博士提到:「在問 AI 之前,先自己想一次。」我想再補充一點:「在問 AI 之前,先自己想過至少一次答案。」

「透過輸出整理學習輸入」的想法,與前一年〈AI 都能寫了,為何我們還要「練鐵人」?〉相同。iT 鐵人賽不只是分享概念或技術本身;這次參賽也帶來意料之外的收穫,例如時間管理、習慣養成和學習方法。關於學習,前面已經提過一些;這次我對學習方法也有更大的改變和收穫,只是很難與大家分享。簡單來說,就是「一口一口吃掉大象」(How do you eat an elephant? One bite at a time!)。在 30 天裡持續思考、學習、寫作,養成輸出的習慣,也學著分配時間與精力。這些都是參加 iT 鐵人賽能額外體驗和獲得的收穫。

完賽以後我是怎麼看待JavaFX?

技術變化很快,JavaFX 以外的跨平台 GUI 選擇提到了不少替代品。在行動裝置普及、智慧穿戴裝置和智慧家電日益增加的環境下,需要考量的也不再只是桌面應用。

Jie_Chung 今年在 COSCUP 分享的主題「編輯器的歷史、現況與未來」提到了使用 Rust 開發的 GPUI 框架。我相信這樣的後起之秀還有很多。

不過,JavaFX 也並非止步不前。年初發布的 JavaFX 27 改善了 macOS 上的渲染管線效能,也加入許多新特性、修正問題並更新組件版本。(注意:這可能和 Java 27 一樣,並非長期支援版本(LTS)。)

此外,JavaFX 背後有 Gluon 和 Oracle 支持;是否有可靠的商業支援,也經常是商業應用需要考量的因素。

JavaFX 不一定是跨平台桌面應用開發的最佳選項,但已經經過時間考驗,是值得考慮的選擇。

有時間我應該也還是會去玩玩Avalonia就是XD

沒有提及到的部分

JavaFX:WebView

JavaFX 也有 WebKit 核心和 WebView 組件,應該可以做到類似 Electron.js 或 Tauri 的用法。Java 8 文件中有相關範例 WebViewSample,我也用 JavaFX 25 編譯並確認可以運行。我還找到 coldnew's blog 上的文章使用 Clojure 和 JavaFX WebView 來打造桌面程式,原本也想用 ABCL 做類似的事情。

JavaFX(Gluon):Scene Builder Kit

Gluon 除了提供 JavaFX SDK 和 Scene Builder 外,還有一個 Scene Builder Kit。我沒有使用過;依據〈Scene Builder Kit深度解析〉,似乎可以將 Scene Builder 直接嵌入自己的 JavaFX 應用中。

ABCL: debugger

ABCL 的 REPL 環境同時也是一個好用的除錯器,前提是得先學會使用。

進入 REPL 環境後,通常會看到提示:輸入 :help 即可檢視說明文件。

CL-USER(1): :help

  COMMAND     ABBR DESCRIPTION
  apropos     ap   apropos
  bt               backtrace n stack frames (default 8)
  cd               change default directory
  cf               compile file(s)
  cload       cl   compile and load file(s)
  continue    cont invoke restart n
  describe    de   describe an object
  error       err  print the current error message
  exit        ex   exit lisp
  frame       fr   set the value of cl:* to be frame n (default 0)
  help        he   print this help
  inspect     in   inspect an object
  istep       i    navigate within inspection of an object
  ld               load a file
  ls               list directory
  macroexpand ma   macroexpand an expression
  package     pa   change *PACKAGE*
  pwd         pw   print current directory
  reset       res  return to top level
  rq               require a module
  trace       tr   trace function(s)
  untrace     untr untrace function(s)

Commands must be prefixed by the command character, which is ':' by default.

以下是幾個常用功能:

  • :apropos <keyword>:查詢包含keyword的符號
  • :describe <value>:查看值的描述文檔
  • :inspect <value>:檢視<value>

特別是經常在除錯的時候使用:

  • :error:顯示當前的錯誤訊息
  • :bt <num>:顯示<num>層呼叫堆疊
  • :frame <num>:提取<num>層frame資訊

我一度找不到存取除錯環境中區域變數的方法,詢問 AI 也沒有得到答案。其實可以用最後一個指令;例如,先提取第 8 層 frame 的資訊:

:fr 8

接著可以將指令的返回值(*)賦給特定變數:

(setf *frame* *)

ABCL:pathname

Java 路徑系統有 file:、jar:file:...! 等形式,也區分相對路徑與絕對路徑。Common Lisp 的 pathname 則有 logical-pathname 和 truename。ABCL 擴充了 pathname,新增 ext:url-pathname 和 ext:jar-pathname。

cl:pathname (基礎檔案路徑)
  ├── cl:logical-pathname (邏輯路徑)
  └── ext:url-pathname (網路 URL 路徑)
      └── ext:jar-pathname (Java JAR 內部的檔案路徑)

這套設計感覺有點複雜。雖然也有 #'uri-encode 和 #'uri-decode,但我用過後覺得不太順手,因此最後沒有另外寫成一篇。

ABCL: 錯誤處理 / 狀況處理

發揮 ABCL 威力建立了一個能在 JavaFX 應用中評估 LISP 表達式的工具,並在更多的 Dialog 類型中用它進行更多探索。

為了方便探索 JavaFX,在後續的使用上,並不是只有在該篇提到的檢查是否有輸入,還使用#'restart-case包裹#'eval來處理例外狀況:

(restart-case (eval (read-from-string _forms))
  (continue nil nil)
  (eval-other-form (other-form)
    :interactive (lambda nil
                   (format t "Other Form: ")
                   (force-output)
                   (list (read)))
    (eval other-form))
  (return-value (new-value)
    :interactive (lambda nil
                   (format t "Return Value: ")
                   (force-output)
                   (list (read-line)))
    new-value))

當輸入的 form 有問題時,這會進入終端機的互動模式,讓我選擇忽略錯誤並直接返回 nil或提供的返回值;也可以選擇換一個 form 重新評估。

Common Lisp 的狀況處理(錯誤處理)很特別;在其他語言中,我幾乎沒見過同等或相近的設計,有些甚至在語言設計層面上,我認為完全不可能實現。我之前寫過一篇相關的快速筆記,一度想再多寫幾篇說明,但最後還是把重心稍微移向 JavaFX。

尾聲

本系列分成四個部分(Session):

第一部分(Session 1)旨在初步認識並準備環境。

第二部分(Session 2)是主要內容,從 HelloFX 開始,介紹第一個互動元件、資源存取、CSS、FXML,再由 ABCL 回到 Java,並打包、分發應用。

第三部分(Session 3)和第四部分(Session 4)則補充更多 JavaFX 與 ABCL 的內容。

系列至此告一段落。對我而言,最大的收穫不只是學習 JavaFX,也是在持續輸出中培養學習與寫作的習慣。希望你也能從中有所收穫。


上一篇
lesson 25(S4): 在 ABCL 中自訂讀取巨集:用 `#L` 簡化建立 Java 物件陣列的方式
系列文
玩轉ABCL Lisp!用奇怪偏門的方式學習JavaFX 共 35 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言