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 GithubGuiServer on GithubETutor on GithubA page about GuiServer on my website, where you can download ready binarieshttps://groups.google.com/d/forum/guiserver - A group to discuss all issues related to GuiServer and External
Article about GuiServer on Habré