-
Notifications
You must be signed in to change notification settings - Fork 647
Getting Started
In this example we will make a program that asks the user to enter their name, then prints it.
The complete code for this program is as follows. I will discuss each part of the code below.
package main
import (
"github.com/andlabs/ui"
)
var window ui.Window
func main() {
go ui.Do(func() {
name := ui.NewTextField()
button := ui.NewButton("Greet")
greeting := ui.NewStandaloneLabel("")
stack := ui.NewVerticalStack(
ui.NewStandaloneLabel("Enter your name:"),
name,
button,
greeting)
button.OnClicked(func() {
greeting.SetText("Hello, " + name.Text() + "!")
})
window = ui.NewWindow("Hello", 200, 100, stack)
window.OnClosing(func() bool {
ui.Stop()
return true
})
window.Show()
})
err := ui.Go()
if err != nil {
panic(err)
}
}
First, we declare a global variable of type ui.Window
. Windows hold other controls; all controls must belong to a Window in order for them to be visible on screen. (A Window is itself not a control.) For technical reasons, we keep the Window global so as to prevent it (and thus its children) from being moved around in memory (as it would have been if it was a stack variable).
You'll notice that all our UI work is done inside a closure passed to the function ui.Do()
. Most windowing systems actually hate being run on multiple threads, so ui.Do()
is a compromise to keep things nice and serialized for the underlying OS. Except for event handlers, all UI code should be passed to ui.Do()
.
We run ui.Do()
as a goroutine because it will wait for the function to finish running before it returns, and we haven't even launched the UI main loop yet.
The next few assignments should be straightforward: we create a text field, a button, and a label where our greeting will go. The only odd thing here is the use of StandaloneLabel
: by default, labels have their positions adjusted so that they look correct when placed to the left of another control. Standalone labels don't have this adjustment, and both the greeting label and the instructional text (added later) stand on their own.
Controls in package ui are arranged using layout containers, similar to how GTK+ and Qt do things. The most basic of these is the stack, which arranges controls horizontally or vertically, giving each control the same height or width (respectively). In this case, we use a vertical stack to arrange our controls vertically. We also add an extra instructional label; since we don't need to do anything with it later, we add it directly without saving it in a variable.
Next, we assign an event handler to run when the button is clicked. Event handlers are simply functions that get run a la ui.Do()
when the event arrives. You can safely work with the UI in an event handler, and invocations of ui.Do()
from other goroutines won't run while an event handler is running. The body of the event handler should be straightforward.
Now we are ready to create the window. ui.NewWindow()
takes four parameters: the title of the window, its width in pixels, its height in pixels, and the control that the window holds. A window can only hold one control, and our stack is a control, so we simply give the stack to the new window. All the controls we created before become part of the window automatically.
Next, we want to quit gracefully when the user closes the window. w.OnClosing()
is an event like the OnClicked()
event earlier, with the exception that the handler returns a boolean value that determines whether the window should be closed. In this case, we merely call ui.Stop()
to schedule a shutdown of the package ui main loop and return true to close the window. The main loop will stop on its own a short time later.
Finally, we have to bring the window on screen to start working with it.
ui.Go()
is the package ui main loop. It initializes the underlying window system, allocating its own resources, and then enters the main loop, not returning until ui.Stop()
is called. (This is also why we use a goroutine for ui.Do()
.) If an error occurs during initialization, it will be returned.
And there you have it! From this point on, the rest of the package should be mostly straightforward. The rest of this wiki will discuss more complex topics.