Go Gio 實戰(zhàn):煮蛋計時器的實現(xiàn) 01 — 空窗口
接下來我們將一步步實通過 gio 實現(xiàn)一個煮蛋計時器。
這是完全從頭開始實現(xiàn)的,使用 Gio 這個 Go GUI 庫實現(xiàn)的獨立 Go 應(yīng)用程序,會解釋每一個步驟。
實現(xiàn)的最終效果如下:

本系列大綱:
第 1 章 - 空窗口 第 2 章 - 標(biāo)題和大小 第 3 章 - 按鈕 第 4 章 - 低按鈕(Low Button) 第 5 章 - 重構(gòu) 第 6 章 - 帶邊距的按鈕 第 7 章 - 進(jìn)度條 第 8 章 - 畫圓 第 9 章 畫雞蛋 第 10 章 - 輸入沸騰時間
先看如何實現(xiàn)一個空窗口。
01 目標(biāo)
本節(jié)的目的是創(chuàng)建一個空白畫布,我們稍后可以在其上進(jìn)行繪制。

02 主要內(nèi)容
本節(jié)代碼主要做三件事:
導(dǎo)入 Gio 創(chuàng)建并調(diào)用 goroutine: 創(chuàng)建一個新窗口: w啟動一個無限循環(huán),等待窗口中的事件,具體事件后續(xù)實現(xiàn)
接下來看看具體的代碼。
03 代碼
package?main
import?(
?"gioui.org/app"
)
func?main()?{
?go?func()?{
??//?創(chuàng)建一個新窗口(Window)
??w?:=?app.NewWindow()
??//?監(jiān)聽窗口的事件
??for?range?w.Events()?{
??}
?}()
?app.Main()
}
04 代碼詳解
代碼看起來很簡單。不過,還是花點時間看看發(fā)生了什么,畢竟 GUI 編程大家接觸的少。
1)我們導(dǎo)入了 gioui.org/app,它干什么用的?
我們需要查看文檔:https://pkg.go.dev/gioui.org/app:
包 app 為運行圖形用戶界面的操作系統(tǒng)功能提供了一個獨立于平臺的界面。
這是很棒的特性。Gio 為我們處理所有與平臺相關(guān)的事情,這和 Go 一樣,是跨平臺的。
這可能比你意識到的要更重要。因為,即使你今天的應(yīng)用程序是單平臺的,但指不定哪天想遷移到其他平臺。
上篇文章簡單介紹了,Gio 對各個平臺都有支持,包括移動端,甚至 tvOS。
2)goroutine 中的事件循環(huán)
事件循環(huán)的代碼是:
for range w.Events(),它循環(huán)監(jiān)聽窗口中的事件?,F(xiàn)在我們只是監(jiān)聽,并沒有對事件做任何處理。后續(xù)章節(jié)會實現(xiàn)。從 app.Main[1] 我們了解到:
因為 Main 在某些平臺上也是阻塞的,所以 Window 的事件循環(huán)必須在 goroutine 中運行。
有 Go 經(jīng)驗的同學(xué)應(yīng)該理解這塊內(nèi)容。因為如果 app.Main 不堵塞,最后 main 函數(shù)就返回,程序退出了。
一個沒有名字的 goroutine,即匿名函數(shù),被創(chuàng)建并運行事件循環(huán)。由于它在 goroutine 中,它將與程序的其余部分同時運行。
go?func?{
??//?...
}()這是 Go 語言常見的寫法。
3)最后上文提到的調(diào)用 app.Main() 啟動程序,app.Main 的文檔提到:
Main 函數(shù)必須從程序的 main 函數(shù)中調(diào)用,以便將主線程的控制權(quán)移交給需要它的操作系統(tǒng)。Main 的具體實現(xiàn),不同系統(tǒng)不一樣。
比如 Unix、Windows 等系統(tǒng),直接調(diào)用 select {},感興趣的可以查看 gio 的源碼。
不過,上面的簡單代碼,在 Mac 下運行不正常,會 panic:
panic:?runtime?error:?invalid?memory?address?or?nil?pointer?dereference
[signal?SIGSEGV:?segmentation?violation?code=0x1?addr=0x0?pc=0x40f7f85]
可以先忽略。如果就想看看,可以用下面代碼:
package?main
import?(
?"gioui.org/app"
?"gioui.org/io/system"
?"gioui.org/layout"
?"gioui.org/op"
)
func?main()?{
?go?func()?{
??w?:=?app.NewWindow()
??var?ops?op.Ops
??for?e?:=?range?w.Events()?{
???switch?e?:=?e.(type)?{
???case?system.FrameEvent:
????gtx?:=?layout.NewContext(&ops,?e)
????e.Frame(gtx.Ops)
???}
??}
?}()
?app.Main()
}
05 小結(jié)
通過 gio 創(chuàng)建 GUI 應(yīng)用程序,和普通服務(wù)端應(yīng)用程序類似:
一個循環(huán),處理各種事件 一個堵塞,好比 select{} 或 HTTP 服務(wù)中的 http.ListenAndServe
趕緊動手試試吧!
參考資料
app.Main: https://pkg.go.dev/gioui.org/app#hdr-Main
推薦閱讀
