📜 ⬆️ ⬇️

GUI on Golang: GTK + 3

I decided to write one cross-platform desktop application on Go . Made a CLI version, everything works fine. Yes, and 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 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.


The application is compiled 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 it will be possible to 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.


It is compiled using the qtdeploy special command. 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 .


If desired, Qt can be achieved so that the interface looks natively on desktop operating systems.


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 as well, and HTML will come in handy.


Compiled with go build , cross- compiling possible with xgo .


Looks natively 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 it 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 simple. And that for nothing about Go say that in it a problem with GUI . But how wrong I was ...


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 main.go code:


 package main import ( "log" "github.com/gotk3/gotk3/gtk" ) func main() { //  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 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 the program code, you can distribute the whole design in Glade . Then save everything to an XML-like * .glade file and load it already through our application.


Install glade


GNU / Linux


Installing the glade in GNU / Linux distributions is not difficult. 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 the main.glade file:


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

That is, we have a window_main window ( GtkWindow ), in which inside a container ( GtkBox ), which contains an entry 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" ) func main() { //  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 are submitting the form with an XML- main.glade file, and the code in 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 the errors that the GetObject() function returns to make the code simpler. 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 of the clicked button (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 there too. If you are interested to see it all now in code, then you can peep 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 someone interesting, I will continue to write.


')

Source: https://habr.com/ru/post/420035/


All Articles