📜 ⬆️ ⬇️

External - GUI for Golang

Greetings, colleagues!

About a month ago, I published here an article on GUI frameworks - to the stream where technology was proposed for creating GUI frameworks for different programming languages ​​based on connecting (tcp / ip or some other) to an external process playing the role of a kind of GUI server. Here I want to present a concrete implementation of this idea - a new GUI framework for Golang - External .

Why was it even necessary to write a new GUI for Golang if there are already quite a few such tools available? First of all, because none of them did not suit me fully. It was necessary to create desktop applications, cross-platform, so that it looked natural for each platform. If possible, not very cumbersome, having a minimum of dependencies - I am committed to a minimalist approach.
')
I was guided by this list . Two positions - app and walk were immediately deleted, as not meeting the requirements of cross-platform. After some thought, he rejected those based on html / css / javascript. Firstly, it seems to me somewhat unusual to build a desktop application as a web page and, secondly, they are pulling the heavy engines behind them. For example, go-astilectron and gowd are based on Electron and nw.js , respectively, and these, in turn, on node.js. Imagine how much should be installed at the end user to run even a small utility? Is that go-sctiter from this point of view looks preferable: the Sciter behind it is not so monstrous.

Go-gtk and gotk3 are based on GTK. This seems to be thoroughly made packages, but I refused them, because, in my opinion, using GTK under Windows is not the best solution. GTK windows do not look native under Windows. Qt binding is a powerful thing, of course, but quite complicated, and the size ... When I read: "You need 2.5 GB free RAM (which was used during the initial setup) and at least 5 GB free disk space", the last doubts have disappeared. Go itself takes ten times less space. And there are also licensing restrictions: “this is a rule.”

What do we have left from the list? Ui might be a good option, but he is still in the mid-alpha stage. Fyne looks good too, but doesn't seem to be ready. It was somewhat embarrassing that, on the one hand, “Fyne is built entirely using vector graphics”, and, on the other, “EFL windows packages are like that. Well, I don’t like that in order to install EFL under Windows (the graphical library on which Fyne is based), MSYS is needed.

In short, with all due respect to the authors of the listed packages and to the products of their work, for myself I did not choose anything and with a clear conscience I started what I wanted to do - write a new GUI framework - External .

As I wrote in the previous article, External does not implement GUI elements on its own, it uses a separate application for this, a separate process acting as a GUI server, this application is called GuiServer . External launches it, joins it via tcp / ip, sends commands / requests to create windows and widgets, manipulate them, etc., and receives messages from it.

Here is the simplest program that creates a window with the traditional Hello, world text:

package main import egui "github.com/alkresin/external" func main() { if egui.Init("") != 0 { return } pWindow := &egui.Widget{X: 100, Y: 100, W: 400, H: 140, Title: "My GUI app"} egui.InitMainWindow(pWindow) pWindow.AddWidget(&egui.Widget{Type: "label", X: 20, Y: 60, W: 160, H: 24, Title: "Hello, world!" }) pWindow.Activate() egui.Exit() } 

The Init () function launches GuiServer and joins it. It can be passed a string parameter that determines, if necessary, the name of GuiServer and the path to it, ip address and port, logging level.

InitMainWindow () creates the main application window with the specified parameters. The AddWidget () method adds a label widget.

Activate () - displays a window on the screen and puts the program into standby mode.
Both windows and widgets are defined in the Widget structure - I did not make separate structures for each object, since I did not find a convenient way to implement this, given that there is no inheritance in Go . This structure includes fields common to most widgets, and map [string] string, where properties specific to a particular object are collected:

 type Widget struct { Parent *Widget Type string Name string X int [...] Font *Font AProps map[string]string aWidgets []*Widget } 

The methods of this structure include the already familiar AddWidget (), as well as SetText (), SetImage (), SetParam (), SetColor (), SetFont (), GetText (), Move (), Enable (), and others. I would like to mention SetCallBackProc () and SetCallBackFunc () - for setting event handlers.
To list here all the functions, structures and methods would be inappropriate, for that is, more precisely. there must be documentation. Let me just say a few, to give some general idea:

Menu (), MenuContext (), EndMenu (), AddMenuItem (), AddMenuSeparator () - a set of functions for creating a menu, main or contextual.
EvalProc (sCode string), EvalFunc (sCode string) transfer Harbor code fragment (can be multi-line) for execution on GuiServer - a kind of implementation of the embedded scripting language.
OpenForm (sPath string) - creates a window based on the description from the xml file created by HwGui Designer.
OpenReport (sPath string) - prints the report based on the description from the xml file created by HwGui Designer.
MsgInfo (), ..., SelectFile (), SelectColor (), SelectFont () - a call to standard messageboxes and dialogs.
InitPrinter () and the set of methods of the Printer: Say (), Box (), Line (), etc. structure provide printing to the printer with the possibility of a preview.

Here is a complete list of currently supported widgets:
label, edit, button, check, radio, radiogr, group, combo, bitmap, line, panel (designed for placing other widgets on it), paneltop, panelbot, ownbtn (ownerdrawn button), splitter, updown, tree, progress, tab, browse (table, as many call it), cedit (edit with advanced features), monthcal.

All of them are listed in the init () function extwidg.go along with additional properties. accessible to each of them - these properties are set via Widget.AProps. Many of the listed widgets have other properties, browse is especially rich in them; they can be set separately using the SetParam () method.

External turned out to be small in volume, it is written in pure Go , it does not pull other packages with it, except for a few standard ones. Cross-platform is provided by GuiServer , which can be compiled under Windows, Linux / Unix, Mac OS. A certain inconvenience is connected with the need to use this external module, which you need to either compile from source, or download it ready from my site and place in the directory specified in the PATH. By the way, it is small - only about one and a half megabytes for Windows and about three for Linux.

How it looks, I will show on the example of a small application ETutor - Golang tutorial. This program presents a collection of Go code snippets in the form of a tree. The code can be edited, run. Nothing fancy, but pretty comfortable. The collection can be replenished, add new collections. Now there are collected (not yet fully) A Tour of Go, Go by Example and a few examples on the External itself. ETutor can also be used to, for example, streamline a set of any utilities on Go. So, screenshots.

Windows 10:



Debian, Gnome:



And finally, the links:

External on Github
GuiServer on Github
ETutor on Github
A page about GuiServer on my website, where you can download ready binaries
https://groups.google.com/d/forum/guiserver - A group to discuss all issues related to GuiServer and External
Article about GuiServer on Habré

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


All Articles