GUI on Golang: GTK + 3

  • Tutorial

I decided to write one cross-platform desktop application on Go . Made a CLI version, everything works fine. Moreover, Go Cross-compilation is supported. Everything is fine in general. But I also needed a GUI version. And then it began ...


Golang gotk3


Library selection (binding) for GUI


The application had to be cross-platform.
Therefore, it should compile under Windows , GNU / Linux and macOS .
The choice fell on such libraries:



Electron and other frameworks that pull Chromium and node.js with them , I threw away as they weigh quite a lot, they also eat up a lot of operating system resources.


Now a little about each library.


gotk3


Binding of the library GTK + 3 . Coverage is not all possibilities, but all the main presence.


Compiled application using the standard go build. Cross-platform compilation is possible, with the exception of macOS . Only with macOS you can compile for this OS, and with macOS you can also compile under Windows + GNU / Linux .


The interface will appear natively for GNU / Linux , Windows (you will need to specify a special theme). For macOS it will not look native. It is possible to get out only if it is a terrible topic that will emulate the native elements of macOS .


therecipe / qt


Binding the Qt 5 library . Support for QML, standard widgets. In general, many people advise this binding.


Compiled using a special command qtdeploy. In addition to the desktop platforms, there are also mobile ones. Crosscompilation takes place using Docker . For Apple operating systems , you can only compile with macOS .


At desire on Qt it is possible to achieve that the interface looked natively on desktop OS.


zserge / webview


The library, which was originally written in C , the author has screwed it to many languages, including Go . Native webview is used to display: Windows - MSHTML , GNU / Linux - gtk-webkit2 , macOS - Cocoa / WebKit . In addition to the Go code, you will need to pee on JS , well, HTML is useful.


Compiled with go build, cross- compilation is possible with xgo .


Looks native can as far as the standard browser allows.


Selection


Why did I choose gotk3 ?


In therecipe / qt, I didn’t like the application’s very complicated build system, they even made a special command.


zserge / webview does not seem to be bad, it will not weigh much, but still this is a webview and there may be standard problems that occur in such applications: something may go somewhere. And this is not Electron , where the advanced Chromium is always bundled , and everything can go to some old Windows . And besides, you also have to write on JS .


gotk3 I chose as something in between. You can build a standard go build, it looks acceptable, and indeed I love GTK + 3 !


In general, I thought everything would be easy. And that for nothing about Go say that in it a problem with GUI . But how am I wrong ...


Getting started


Install everything from gotk3 ( gtk , gdk , glib , cairo ) to yourself:


go get github.com/gotk3/gotk3/...

Also, your system should have the GTK + 3 library itself in development.


GNU / Linux


In Ubuntu :


sudo apt-get install libgtk-3-dev

In Arch Linux :


sudo pacman -S gtk3

macOS


Via Homebrew :


 brew install gtk-mac-integration gtk+3

Windows


Everything is not so simple here. The official instructions suggest using MSYS2 and already do everything in it. Personally, I wrote code on other operating systems, and did cross-compilation for Windows in Arch Linux , which I hope to write soon.


Simple example


Now we write a small file with the code main.go:


package main
import (
    "log""github.com/gotk3/gotk3/gtk"
)
funcmain() {
    // Инициализируем GTK.
    gtk.Init(nil)
    // Создаём окно верхнего уровня, устанавливаем заголовок// И соединяем с сигналом "destroy" чтобы можно было закрыть// приложение при закрытии окна
    win, err := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
    if err != nil {
        log.Fatal("Не удалось создать окно:", err)
    }
    win.SetTitle("Простой пример")
    win.Connect("destroy", func() {
        gtk.MainQuit()
    })
    // Создаём новую метку чтобы показать её в окне
    l, err := gtk.LabelNew("Привет, gotk3!")
    if err != nil {
        log.Fatal("Не удалось создать метку:", err)
    }
    // Добавляем метку в окно
    win.Add(l)
    // Устанавливаем размер окна по умолчанию
    win.SetDefaultSize(800, 600)
    // Отображаем все виджеты в окне
    win.ShowAll()
    // Выполняем главный цикл GTK (для отрисовки). Он остановится когда// выполнится gtk.MainQuit()
    gtk.Main()
}

You can compile using the command go build, and then run the binary. But we just run it:


go run main.go

After launch, we get a window of this type:


A simple example on Golang gotk3


Congratulations! You have a simple app from README gotk3 !


More examples can be found on Github gotk3 . I will not disassemble them. Let's better deal with what is not in the examples!


Glade


There is such a thing for Gtk + 3 - Glade . This is the GUI Designer for GTK + . It looks like this:


Glade


In order not to create each element manually and not to place it somewhere in the window with the help of a program code, you can distribute the entire design in Glade . Then save everything to an XML-like * .glade file and load it already through our application.


Install glade


GNU / Linux


It is easy to install the glade in GNU / Linux distributions . In some Ubuntu it will be:


sudo apt-get install glade

In Arch Linux :


sudo pacman -S glade

macOS


In downloads from the official site is very old build. Therefore, it is better to install via Homebrew :


brew install glade

And then run:


glade

Windows


You can download the latest version here . I personally did not install it on Windows at all, so I don’t know about the stability of Glade work there .


Simple application using Glade


In general, I designed a window like this:


Glade


Saved and received file main.glade:


<?xml version="1.0" encoding="UTF-8"?><!-- Generated with glade 3.22.1 --><interface><requireslib="gtk+"version="3.20"/><objectclass="GtkWindow"id="window_main"><propertyname="title"translatable="yes">Пример Glade</property><propertyname="can_focus">False</property><child><placeholder/></child><child><objectclass="GtkBox"><propertyname="visible">True</property><propertyname="can_focus">False</property><propertyname="margin_left">10</property><propertyname="margin_right">10</property><propertyname="margin_top">10</property><propertyname="margin_bottom">10</property><propertyname="orientation">vertical</property><propertyname="spacing">10</property><child><objectclass="GtkEntry"id="entry_1"><propertyname="visible">True</property><propertyname="can_focus">True</property></object><packing><propertyname="expand">False</property><propertyname="fill">True</property><propertyname="position">0</property></packing></child><child><objectclass="GtkButton"id="button_1"><propertyname="label"translatable="yes">Go</property><propertyname="visible">True</property><propertyname="can_focus">True</property><propertyname="receives_default">True</property></object><packing><propertyname="expand">False</property><propertyname="fill">True</property><propertyname="position">1</property></packing></child><child><objectclass="GtkLabel"id="label_1"><propertyname="visible">True</property><propertyname="can_focus">False</property><propertyname="label"translatable="yes">This is label</property></object><packing><propertyname="expand">False</property><propertyname="fill">True</property><propertyname="position">2</property></packing></child></object></child></object></interface>

That is, we got a window window_main( GtkWindow) in which inside the container ( GtkBox), which contains an input field entry_1( GtkEntry), a button button_1( GtkButton) and a label label_1( GtkLabel). In addition, there are still attributes of sampling (I set up a bit), visibility and other attributes that Glade added automatically.


Let's now try to download this presentation in our main.go:


package main
import (
    "log""github.com/gotk3/gotk3/gtk"
)
funcmain() {
    // Инициализируем GTK.
    gtk.Init(nil)
    // Создаём билдер
    b, err := gtk.BuilderNew()
    if err != nil {
        log.Fatal("Ошибка:", err)
    }
    // Загружаем в билдер окно из файла Glade
    err = b.AddFromFile("main.glade")
    if err != nil {
        log.Fatal("Ошибка:", err)
    }
    // Получаем объект главного окна по ID
    obj, err := b.GetObject("window_main")
    if err != nil {
        log.Fatal("Ошибка:", err)
    }
    // Преобразуем из объекта именно окно типа gtk.Window// и соединяем с сигналом "destroy" чтобы можно было закрыть// приложение при закрытии окна
    win := obj.(*gtk.Window)
    win.Connect("destroy", func() {
        gtk.MainQuit()
    })
    // Отображаем все виджеты в окне
    win.ShowAll()
    // Выполняем главный цикл GTK (для отрисовки). Он остановится когда// выполнится gtk.MainQuit()
    gtk.Main()
}

Run again:


go run main.go

And we get:


Golang Glade gotk3


Hooray! Now we form submission hold XML -like main.gladefile and code main.go!


Signals


The window starts up, but let's add interactivity. Let the text from the input field when you click on the button will fall into the label.


To do this, first we get the elements of the input field, the button and the label in the code:


// Получаем поле ввода
obj, _ = b.GetObject("entry_1")
entry1 := obj.(*gtk.Entry)
// Получаем кнопку
obj, _ = b.GetObject("button_1")
button1 := obj.(*gtk.Button)
// Получаем метку
obj, _ = b.GetObject("label_1")
label1 := obj.(*gtk.Label)

I do not handle errors that the function returns GetObject()in order to make the code more simple. But in a real working application they must be processed.


Good. With the code above, we get our form elements. And now let's process the signal clickedbutton (when the button is pressed). The GTK + signal is essentially a reaction to an event. Add the code:


// Сигнал по нажатию на кнопку
button1.Connect("clicked", func() {
    text, err := entry1.GetText()
    if err == nil {
        // Устанавливаем текст из поля ввода метке
        label1.SetText(text)
    }
})

Now run the code:


go run main.go

After entering some text in the field and clicking on the Go button, we will see this text in the label:


Golang Glade gotk3 signal


Now we have an interactive application!


Conclusion


At this stage, everything seems simple and does not cause difficulties. But I had difficulties with cross- compilation (after all, gotk3 compiles with CGO ), integration with operating systems and the file selection dialog. I even added a native dialogue to the gotk project . Also in my project needed internationalization. There are some features too. If you are interested to see it all now in code, then you can see here .


The source codes of the examples from the article are here .


And if you want to read the sequel, you can vote. And if it turns out to be interesting to someone, I will continue to write.

Only registered users can participate in the survey. Sign in , please.

Keep writing?


Also popular now: