Write a calculator program using fyne

Keywords: Go github calculator Windows Programming

brief introduction

In the previous article, we introduced fyne, a high-skin GUI library for Go.This article goes on to show how to write a simple calculator program using fyne.The program works as follows:

Control Layout

We useWidget.EntryTo display the input numbers, operators, and operation results.Create one firstWidget.EntryObject, set to display multiple lines:

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

Other numeric and symbol controls useWidget.ButtonTo represent.Buttons are also divided into two types, one is no special effect, click directly after the corresponding characters can be added to the display box.One has special effects, such as emptying the display box (AC), calculating (=).The middle three line buttons are the first one, and we use GridLayout to lay out four buttons per line:

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(

The input callback is described later.

The first line has three buttons with special effects:

  • AC: Empty the display box;
  • +/-: toggle sign;
  • % changes the number to a percentage, that is, divided by 100.

Plus a division button.This line also uses the GridLayout layout:

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

Several callbacks are introduced later.

The last line because 0 is twice as wide as the other buttons.First, we use the GridLayout layout to divide this row equally into two Grids (two controls per row).Button 0 has a single Grid, and since each Grid in the GridLayout layout is the same size, button 0 has half the width of the entire row.The latter Grid, the button. and = bisect, also uses a GridLayout to achieve this effect:

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

Finally, we'll put all the parts together in a vertical BoxLayout:

container := fyne.NewContainerWithLayout(

In practical development, multiple layouts are often combined to achieve interface effects.

Button response

The Empty button responds simply by setting the Text of the display box to empty:

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

Note that to call Entry.Refresh() Method refresh interface.Since the button response operates on the display box, the object needs to be passed in.

We designed to display two rows in the display box, the first is the expression that was last calculated, and the second is this time.Toggle sign Toggle the sign of a number when only one number is entered this time:

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

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

Input callbacks are handled simply by splicing the corresponding strings into the display box:

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

The function for calculating expressions is also simple, and I use the govaluate library here (see my previous articles):

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

    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

Notice that there is a bit of error tolerance and the extra operators are removed.Also, for display purposes, we used_for division symbols and * for multiplication symbols.To use govaluate, you must replace them with/and*, respectively.

Now that the calculator is written, let's show you how to package it.


Prepare a picture resource as an icon and place it in the project directory:


$ fyne package -os windows -icon icon.jpg

A.exe file and a.syso file were generated in the same directory.Now you can click directlyCalculator.exeRun the program without any other dependencies.


This paper describes how to write a simple calculator program using fyne, mainly how to combine multiple layouts.Of course, calculator functions and error handling are not perfect, and partial process programming can be implemented, which can be improved by itself if you are interested.The full code is in fyne/calculator.

If you find a fun and useful GoLanguage Library, you are welcome to submit your issue on GitHub, the GoDaily Library_

Reference resources

  1. fyne GitHub: https://github.com/fyne-io/fyne
  2. fyne website: https://fyne.io/
  3. Official Introduction to fyne: https://developer.fyne.io/tour/introduction/hello.html
  4. Go Daily Library of GitHub: https://github.com/darjun/go-daily-lib


My blog: https://darjun.github.io

Welcome to my WeChat Public Number GoUpUp to learn and progress together.

Posted by hrichman on Thu, 18 Jun 2020 18:32:58 -0700