📢 This article was translated by gemini-3.5-flash
In December 2024, I tried writing my very first Windows GUI software, Stop Looking at the Screen, Go walk (去散æ¥).
Although it was very simple, it felt like my first time developing without relying heavily on a framework. At the same time, I was determined to use Go no matter what back then. I happened to find a framework that fit the theme so well, creating a pun that echoed the theme with the tech stack.
So looking back at these notes today brings back a lot of feelings. Especially since this software even supports i18n. In today’s era of AI Coding, it’s hard to imagine that I actually hand-coded multi-language support back then using traditional methods, especially since I recall this framework didn’t support it natively. But because it wasn’t very user-friendly, I’ve forgotten how I did it.
That’s it for my reflections. Below are the original notes.
This article is only for publishing the notes from that time and does not guarantee accuracy. Additionally, the walk architecture is not recommended.
Environment
After creating a new Go project in GoLand, go.mod will be initialized by default. If this file does not exist, you can use the command:
Install walk:
1
| go get github.com/tailscale/walk
|
Project
After downloading the
rsrc tool
and configuring the PATH, install rsrc:
1
| go get github.com/akavel/rsrc
|
Create a Manifest file main.manifest with the following content:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="SomeFunkyNameHere" type="win32"/>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/>
</dependentAssembly>
</dependency>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True</dpiAware>
</windowsSettings>
</application>
</assembly>
|
Merge into the Go program:
1
| rsrc -manifest main.manifest -o rsrc.syso
|
Countdown Development
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
| package main
import (
"fmt"
"github.com/tailscale/walk"
. "github.com/tailscale/walk/declarative"
"log"
"runtime"
"time"
)
func main() {
app, err := walk.InitApp()
if err != nil {
log.Fatal(err)
}
var timeRemain *walk.Label
var flag bool
ok := true
MainWindow{
Title: "Hi walk", // Window title
MinSize: Size{Width: 60, Height: 40}, // Minimum size
Layout: VBox{MarginsZero: true}, // Window layout, vertical box layout
Children: []Widget{
Label{
AssignTo: &timeRemain,
Text: "Start countdown 10 seconds",
},
PushButton{
Text: "Start Countdown",
OnClicked: func() {
if flag {
return
}
flag = true
// Countdown
go func() {
for i := 10; i > 0; i-- {
if ok {
time.Sleep(1 * time.Second)
timeRemain.SetText(fmt.Sprintf("Countdown %d seconds", i))
} else {
runtime.Goexit()
}
}
walk.MsgBox(nil, "Reminder", "Time's up", walk.MsgBoxIconInformation)
flag = false
}()
},
},
PushButton{
Text: "Stop Countdown",
OnClicked: func() {
flag = false
ok = false
timeRemain.SetText("Countdown stopped")
time.Sleep(1 * time.Second)
timeRemain.SetText("Start countdown 10 seconds")
},
},
},
}.Create()
app.Run()
}
|
New Window
Open a new window:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
| package main
import (
"github.com/tailscale/walk"
. "github.com/tailscale/walk/declarative"
"log"
)
type MyMainWindow struct {
*walk.MainWindow
}
func main() {
app, err := walk.InitApp()
if err != nil {
log.Fatal(err)
}
mw := new(MyMainWindow)
MainWindow{
AssignTo: &mw.MainWindow,
Title: "Hi walk", // Window title
MinSize: Size{Width: 400, Height: 500}, // Minimum size
Size: Size{Width: 400, Height: 500}, // Size
Layout: VBox{}, // Window layout
Children: []Widget{
Label{
Text: "Please select a mode",
Alignment: AlignHCenterVCenter,
},
PushButton{
Text: "Short-time high-frequency break",
OnClicked: mw.shortLayout,
},
PushButton{
Text: "Long-time low-frequency break",
},
},
}.Create()
app.Run()
}
func (mw *MyMainWindow) shortLayout() {
shortMainWindow := new(MyMainWindow)
MainWindow{
AssignTo: &shortMainWindow.MainWindow,
Title: "Short-time high-frequency break",
MinSize: Size{Width: 400, Height: 500}, // Minimum size
Size: Size{Width: 400, Height: 500}, // Size
Layout: VBox{},
Children: []Widget{
Label{Text: "Hello"},
},
}.Create()
shortMainWindow.Running()
}
|
Reference
Two days of using go walk, silently giving up in my heart
Golang—walk learning (1)
walk control learning section 1