专栏首页GoUpUp使用 fyne 编写一个计算器程序

使用 fyne 编写一个计算器程序

简介

在上一篇文章中,我们介绍了一个 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?

参考

  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

本文分享自微信公众号 - GoUpUp(GoUp-Up),作者:dj

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-06-19

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Go 每日一库之 fyne

    Go 语言生态中,GUI 一直是短板,更别说跨平台的 GUI 了。fyne向前迈了一大步。fyne 是 Go 语言编写的跨平台的 UI 库,它可以很方便地移植到...

    用户7731323
  • Go 每日一库之 nutsdb

    nutsdb是一个完全由 Go 编写的简单、快速、可嵌入的持久化存储。nutsdb与我们之前介绍过的buntdb有些类似,但是支持List、Set、Sorted...

    用户7731323
  • Go 每日一库之 plot

    本文介绍 Go 语言的一个非常强大、好用的绘图库——plot。plot内置了很多常用的组件,基本满足日常需求。同时,它也提供了定制化的接口,可以实现我们的个性化...

    用户7731323
  • CentOS 7 部署RabbitMQ 服务

    版权声明:本文为木偶人shaon原创文章,转载请注明原文地址,非常感谢。 https://b...

    shaonbean
  • 7-开发板接入小五物联实现远程控制(Air202模块+单片机)

    这一节为教程最终版功能演示,现在不必深究,早晚自己全部都会实现的(静静的跟着我学哈)

    杨奉武
  • js事件循环

    之前有看过一些事件循环的博客,不过一阵子没看就发现自己忘光了,所以决定来自己写一个博客总结下!

    嘿嘿嘿
  • 7-开发板接入小五物联实现远程控制(Air202模块+单片机)

    https://www.cnblogs.com/yangfengwu/p/9337033.html

    杨奉武
  • Flutter 实现虎牙/斗鱼 弹幕效果

    弹幕的实现原理非常简单,即将一条弹幕从左侧平移到右侧,当然我们要计算弹幕垂直方向上的偏移,不然所有的弹幕都会在一条直线上,相互覆盖。平移代码如下:

    老孟Flutter
  • Flutter 实现虎牙/斗鱼 弹幕功能

    弹幕的实现原理非常简单,即将一条弹幕从左侧平移到右侧,当然我们要计算弹幕垂直方向上的偏移,不然所有的弹幕都会在一条直线上,相互覆盖。平移代码如下:

    砸漏
  • 安卓逆向系列教程(三)静态分析工具

    几年之前,我们要破解 APK,可能需要用到 apktool、dex2jar、jd-gui 以及 smali2java 等工具。还需要在控制台中键入命令,但现在有...

    ApacheCN_飞龙

扫码关注云+社区

领取腾讯云代金券