簡介

在之前文章中,我們介紹了一個 Go 的高顏值 GUI 庫 fyne 。本文接着,介紹如何使用 fyne 編寫一個簡單的計算器程序。程序效果如下:

控件佈局

我們使用 widget.Entry 來顯示輸入的數字、運算符和運算結果。先創建一個 widget.Entry 對象,設置可顯示多行:

display := widget.NewEntry()
display.MultiLine = true

其它數字和符號控件都用 widget.Button 來表示。按鈕也分爲兩種,一種是沒有特殊效果的,點擊後直接在顯示框中添加對應的字符即可。一種是有特殊效果的,例如清空顯示框( AC )、進行計算( = )。中間三行按鈕都是前一種,我們使用 GridLayout 來佈局,每行顯示 4 個:

digits := []string{
  "7", "8", "9", "×",
  "4", "5", "6", "-",
  "1", "2", "3", "+",
}
var digitBtns []fyne.CanvasObject
for _, val := range digits {
  digitBtns = append(digitBtns, widget.NewButton(val, input(display, val)))
}
digitContainer := fyne.NewContainerWithLayout(
  layout.NewGridLayout(4),
  digitBtns...)

input 回調後面介紹。

第一行有 3 個具有特殊效果的按鈕:

  • AC :清空顯示框;
  • +/- :切換正負號;
  • % 將數字變爲百分數,即除以 100。

外加一個除法按鈕。這一行同樣使用 GridLayout 佈局:

clearBtn := widget.NewButton("AC", clear(display))
signBtn := widget.NewButton("+/-", sign(display))
percentBtn := widget.NewButton("%", percent(display, "%"))
divideBtn := widget.NewButton("÷", input(display, "÷"))
clearContainer := fyne.NewContainerWithLayout(
  layout.NewGridLayout(4),
  clearBtn,
  signBtn,
  percentBtn,
  divideBtn,
)

幾個回調處理後面統一介紹。

最後一行由於 0 這個按鈕寬度是其它按鈕的 2 倍。我們先使用 GridLayout 佈局,將這一行平均分成兩 Grid (即每行 2 個控件)。按鈕 0 獨佔一個 Grid ,由於 GridLayout 佈局中每個 Grid 大小相同,故按鈕 0 有整個行一半的寬度。後一個 Grid ,按鈕 .= 平分,同樣使用一個 GridLayout 達到這個效果:

zeroBtn := widget.NewButton("0", input(display, "0"))
dotBtn := widget.NewButton(".", input(display, "."))
equalBtn := widget.NewButton("=", equals(display))
zeroContainer := fyne.NewContainerWithLayout(
  layout.NewGridLayout(2),
  zeroBtn,
  fyne.NewContainerWithLayout(
    layout.NewGridLayout(2),
    dotBtn,
    equalBtn,
  ),
)

最後我們將所有部分用垂直的 BoxLayout 組合到一起:

container := fyne.NewContainerWithLayout(
  layout.NewVBoxLayout(),
  display,
  clearContainer,
  digitContainer,
  zeroContainer,
  copyright,
)

在實際開發中,一般會組合使用多種佈局實現界面效果。

按鈕響應

清空按鈕響應比較簡單,直接將顯示框的 Text 設置爲空即可:

func clear(display *widget.Entry) func() {
  return func() {
    display.Text = ""
    display.Refresh()
  }
}

注意,要調用 Entry.Refresh() 方法刷新界面。由於按鈕響應都是對應顯示框進行操作,所以都需要傳入該對象。

我們設計在顯示框中顯示兩行,第一行是上次計算的表達式,第二行是本次的。切換正負號在本次只輸入一個數字時將該數字的正負號進行切換:

func sign(display *widget.Entry) func() {
  return func() {
    lines := strings.Split(display.Text, "\n")
    if len(lines) == 0 {
      return
    }

    line := lines[len(lines)-1]
    value, err := strconv.ParseInt(line, 10, 64)
    if err != nil {
      return
    }
    lines[len(lines)-1] = strconv.FormatInt(-value, 10)
    display.Text = strings.Join(lines, "\n")
  }
}

輸入回調我們只做了簡單的處理——將對應字符串拼接到顯示框中:

func input(display *widget.Entry, value string) func() {
  return func() {
    display.Text += value
    display.Refresh()
  }
}

計算表達式的函數也很簡單,我這裏使用了 govaluate 庫(可以看我之前的文章):

func equals(display *widget.Entry) func() {
  return func() {
    lines := strings.Split(display.Text, "\n")
    if len(lines) == 0 {
      return
    }

    line := lines[len(lines)-1]
    line = strings.Trim(line, "+÷×")
    exprLine := strings.Replace(line, "÷", "/", -1)
    exprLine = strings.Replace(exprLine, "×", "*", -1)
    expr, _ := govaluate.NewEvaluableExpression(exprLine)
    result, _ := expr.Evaluate(nil)
    line += "=\n"
    line += fmt.Sprint(result)
    display.Text = line
    display.Refresh()
  }
}

注意,這裏做了一點容錯,把前後多餘的運算符去掉了。另外,我們前面爲了顯示,使用了 ÷ 表示除法符號, × 表示乘法符號。要使用 govaluate ,必須將它們分別替換爲 /*

至此計算器就編寫完成了,下面我們介紹如何打包。

打包

準備好一張圖片資源作爲圖標,放到項目目錄下:

打包:

$ fyne package -os windows -icon icon.jpg

在同目錄下生成了一個 .exe 文件和一個 .syso 文件。現在可直接點擊 calculator.exe 運行程序,沒有其他依賴。

總結

本文介紹如何使用 fyne 編寫一個簡單的計算器程序,主要介紹如何組合使用多種佈局。當然計算器功能和錯誤處理還不完善,而且實現偏過程式編程,感興趣的可自行完善。完整代碼在 fyne/calculator 中。

大家如果發現好玩、好用的 Go 語言庫,歡迎到 Go 每日一庫 GitHub 上提交 issue:smile:

參考

  1. fyne GitHub:https://github.com/fyne-io/fyne

  2. fyne 官網:https://fyne.io/

  3. fyne 官方入門教程:https://developer.fyne.io/tour/introduction/hello.html

  4. Go 每日一庫 GitHub:https://github.com/darjun/go-daily-lib

推薦閱讀

喜歡本文的朋友,歡迎關注“ Go語言中文網

Go 語言中 文網啓用 信學習交流羣,歡迎加微信 274768166 ,投稿亦歡迎

相關文章