(原) Golang之GUI: gotk3

原创文章,请后转载,并注明出处。

考虑可能需要开发资源管理器/图片管理器,继续寻找golang的gui解决方案。

Github

这里有例程,我们都喜欢文档详细,例程多的东西。

依赖: sudo apt install libgtk-3-dev libcairo2-dev libglib2.0-dev

这里也讲了win环境下的安装。

网友的学习文章读一读

一 外带简单示例

第一次运行例程simple,好几分钟才出来,第二次运行就快多了。也不知道它内部在干啥。

package main

import (
	"log"

	"github.com/gotk3/gotk3/gtk"
)

func main() {
	gtk.Init(nil)  // 初始化GTK而不解析任何命令行参数。

    //创建顶层窗口,当销毁时关联退出事件
	win, err := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)  。
	if err != nil {
		log.Fatal("Unable to create window:", err)
	}
	win.SetTitle("Simple Example")
	win.Connect("destroy", func() {
		gtk.MainQuit()
	})

	// 添加标签控件
	l, err := gtk.LabelNew("Hello, gotk3!")
	if err != nil {
		log.Fatal("Unable to create label:", err)
	}

	// 控件加到窗口中
	win.Add(l)

	// 窗口大小
	win.SetDefaultSize(800, 600)

	// 递归显示此窗口中包含的所有小部件。
	win.ShowAll()

	// 开始主循环
	gtk.Main()
}

中文显示正常

二 库带小示例

看起来这个例子与库README中介绍的有点不同,看看:

import (
	"log"
	"os"

	"github.com/gotk3/gotk3/glib"
	"github.com/gotk3/gotk3/gtk"
)

func main() {
	const appID = "org.gtk.example"
	application, err := gtk.ApplicationNew(appID, glib.APPLICATION_FLAGS_NONE)
	if err != nil {
		log.Fatal("Could not create application.", err)
	}
	//关联激活事件
	application.Connect("activate", func() { onActivate(application) })
	os.Exit(application.Run(os.Args))
}

func onActivate(application *gtk.Application) {
	appWindow, err := gtk.ApplicationWindowNew(application)
	if err != nil {
		log.Fatal("Could not create application window.", err)
	}
	//设置窗口相关属性
	appWindow.SetTitle("简单应用窗口")
	appWindow.SetDefaultSize(400, 400)
	appWindow.Show()
}

代码还是容易理解。appID这个感觉有点象安卓App,给每个程序一个标识,一般使用公司域名。

或者以下代码也是一样。

package main

import (
	"log"
	"os"

	"github.com/gotk3/gotk3/glib"
	"github.com/gotk3/gotk3/gtk"
)

func main() {
	const appID = "org.gtk.example"
	application, err := gtk.ApplicationNew(appID, glib.APPLICATION_FLAGS_NONE)
	if err != nil {
		log.Fatal("Could not create application.", err)
	}

	application.Connect("activate", func() {
		appWindow, err := gtk.ApplicationWindowNew(application)
		if err != nil {
			log.Fatal("Could not create application window.", err)
		}
		appWindow.SetTitle("Basic Application.")
		appWindow.SetDefaultSize(400, 400)
		appWindow.Show()
	})
	application.Run(os.Args)
}

三 按钮控件

添加按钮

package main

import (
	"fmt"
	"github.com/gotk3/gotk3/glib"
	"github.com/gotk3/gotk3/gtk"
	"log"
	"os"
)

//这部分是相同的
func main() {
	const appId = "com.nayoso.example"
	app, err := gtk.ApplicationNew(appId, glib.APPLICATION_FLAGS_NONE)

	if err != nil {
		log.Fatal("Could not create application.", err)
	}

	app.Connect("activate", func() {
		onActivate(app)
	} )

	app.Run(os.Args)
}

//
func onActivate(application *gtk.Application) {

	appWindow, err := gtk.ApplicationWindowNew(application)
	if err != nil {
		log.Fatal("Could not create application window.", err)
	}
	appWindow.SetTitle("Basic Application.")
	appWindow.SetDefaultSize(400, 400)

	buttonBox, err := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 2)		//以水平布局创建一个容器, 第二个参数是其中控件的像素间隔
	if err != nil {
		log.Fatal(err)
	}
	appWindow.Add(buttonBox)	//将布局添加到window中

	button, err := gtk.ButtonNewWithLabel("Hello World")		//创建一个按钮
	if err != nil {
		log.Fatal(err)
	}
	buttonBox.Add(button)		//将按钮添加到box容器中

	button.Connect("clicked", func() {	//让我们为按钮点击添加一个函数,每次点击都会在命令行输出Hello World
		fmt.Println("Hello World")
		appWindow.Destroy()		//摧毁窗口
	})

	appWindow.ShowAll()		//与Show()不同在于,它会输出Window中的子控件。你可以修改,查看不同的效果
}

四 布局

看看布局的例子:

package main

import (
	"os"

	"github.com/gotk3/gotk3/glib"
	"github.com/gotk3/gotk3/gtk"
)

func main() {
	const appId = "com.nayoso.example"

	app, _ := gtk.ApplicationNew(appId, glib.APPLICATION_FLAGS_NONE)
	app.Connect("activate", func() {
		onActivate(app)
	})
	app.Run(os.Args)
}

func onActivate(application *gtk.Application) {
	appWindow, _ := gtk.ApplicationWindowNew(application)
	appWindow.SetTitle("Grid example")
	//-- 以上,通常的代码输入完了,接下就是这个例子的重点

	grid, _ := gtk.GridNew() //创建容器
	appWindow.Add(grid)      //将容器添加到window中

	//现在再让我们创建一些按钮来展示grid的效果
	button1, _ := gtk.ButtonNewWithLabel("Button 1")
	button2, _ := gtk.ButtonNewWithLabel("Button 2")
	button3, _ := gtk.ButtonNewWithLabel("Button 3")
	button4, _ := gtk.ButtonNewWithLabel("Button 4")
	//将buttons添加到grid中
	grid.Attach(button1, 0, 0, 1, 1) //参数:左,上,宽,高
	grid.Attach(button2, 1, 0, 1, 1)
	grid.Attach(button3, 0, 1, 2, 1)
	grid.Attach(button4, 0, 2, 1, 1)
	//-- 注意一下,按钮的位置就像在一个坐标轴中,原点在左上,x轴向右,y轴向下

	appWindow.ShowAll()
}

五 界面编辑

据说,可以通过GtkBuilder使用XML构建UI。

我的Ubuntu上是啥时候装上的?(sudo apt-get install glade) 运行 glade 就弹出了。

package main

import (
	"log"
	"os"

	"github.com/gotk3/gotk3/glib"
	"github.com/gotk3/gotk3/gtk"
)

func main() {
	const appId = "com.nayoso.example"

	app, _ := gtk.ApplicationNew(appId, glib.APPLICATION_FLAGS_NONE)
	app.Connect("activate", func() {
		onActivate(app)
	})
	app.Run(os.Args)
}

//-- 在开始我们还是使用我们熟悉的代码

func onActivate(application *gtk.Application) {
	if builder, err := gtk.BuilderNewFromFile("builder.ui"); err != nil { //从文件中创建Builder
		log.Fatal(err)
	} else if winObj, err := builder.GetObject("window"); err != nil { //从文件中读取window对象,其实际上是Gobject
		log.Fatal(err)
	} else {
		window := winObj.(*gtk.Window) //由于winObj是Gobject,所以我们使用类型断言得到Gtk.Window对象
		application.AddWindow(window)  //记得将window加入我们的application中

		window.ShowAll()
	}
}

主菜ui

<interface>
    <object id="window" class="GtkWindow">
        <property name="visible">True</property>
        <property name="title">Grid</property>
        <property name="border-width">10</property>
        <child>
            <object id="grid" class="GtkGrid">
                <property name="visible">True</property>
                <child>
                    <object id="button1" class="GtkButton">
                        <property name="visible">True</property>
                        <property name="label">Button 1</property>
                    </object>
                    <packing>
                        <property name="left-attach">0</property>
                        <property name="top-attach">0</property>
                    </packing>
                </child>
                <child>
                    <object id="button2" class="GtkButton">
                        <property name="visible">True</property>
                        <property name="label">Button 2</property>
                    </object>
                    <packing>
                        <property name="left-attach">1</property>
                        <property name="top-attach">0</property>
                    </packing>
                </child>
                <child>
                    <object id="quit" class="GtkButton">
                        <property name="visible">True</property>
                        <property name="label">Quit</property>
                    </object>
                    <packing>
                        <property name="left-attach">0</property>
                        <property name="top-attach">1</property>
                        <property name="width">2</property>
                    </packing>
                </child>
            </object>
            <packing>
            </packing>
        </child>
    </object>
</interface>

运行后就可以看到上图中设计的样子了。

看起来ui设计器有点“博大精深”,稍后再研究。先把示例代码研究一翻。特别是去发现是否依然存在不能输入中文的问题。

看起来并没有异常。仿佛就是它。

找到一些资源

github上搜索gogtk3,会有一些示例

GTK3 Glade示例

示例

网络通信实例

相关文章