互联网上已经涌现出不少成熟、好用的第三方GUI界面库。
https://github.com/avelino/awesome-go#gui
GTK2
GTK+ 是一种面向对象式的API(applicationprogramming interface)。Glib 是GTK+的基础,而这种“面向对象系统”正是由“Glib”来提供的。GTK+ 是一种函数库是用来帮助制作图形交互界面的,同时遵循 LGPL 许可证。
GTK2:https://github.com/mattn/go-gtk
- 工具:Glade
- 布局
常用控件选择区:列举了常用的控件,常用的有三类:顶层(主窗口等),容器(各种布局容器等),控制和显示(按钮、便签、图片控件等)
界面编辑区:把控件拖放在这进行进行相应的布局
控件监视区:能够看到界面上所有的控件,同时,选中这个控件,可以看到这个控件的具体类型
属性编辑区:编辑选中控件的常用属性,如窗口设置标题、窗口类型、屏幕上显示位置等。
工具栏:常用的有以下几个按钮
新建:新建一个glade文件
打开:打开一个已经存在的glade文件
保存:保存一个glade文件
选择:按了这个按钮, 才能选择控件
拖拽调整大小:按了这个按钮,才能移动控件的位置,改变控件的大小
- Glade的操作
选择控件时,一定要先按工具栏的“选择”按钮
操作时,支持撤销(Ctrl+z)和恢复(Ctrl+y)等window的快捷键
操作的流程和布局的过程是一致的:
1.选择主窗口,根据需要设置窗口的相应属性
- 选择布局容器
- 根据需要选择相应的控件,根据需要设置控件的相应属性
- 环境搭建(windows)
- 下载安装msys2
官方网址:http://www.msys2.org/
- 安装所需软件
安装gtk3:
pacman -S mingw-w64-x86_64-gtk3
安装gtk2:
pacman -S mingw-w64-x86_64-gtk2
安装glade
pacman -S mingw-w64-x86_64-glade
安装帮助文档
pacman -S mingw-w64-x86_64-devhelp
安装MinGW
pacman -S mingw-w64-x86_64-toolchain base-devel
- 配置环境变量
配置:
PATH:
C:\msys64\usr\bin
C:\msys64\mingw64\bin
测试:
pkg-config --cflags gtk+-2.0
make -v
- 下载依赖
//官方
# go get github.com/mattn/go-gtk/gtk
//国内 放在GOPATH目录src下
# git clone https://github.com/mattn/go-gtk
# cd go-gtk
# make install
# make example
# ./example/demo/demo
- 运行官方demo
# cd $GOPATH/github.com/mattn/go-gtk/example/demo
# go build demo.go
# demo.exe
- 导入依赖
import (
"github.com/mattn/go-gtk/gdkpixbuf"
"github.com/mattn/go-gtk/glib"
"github.com/mattn/go-gtk/gtk"
)
- 控件
控件是对数据和方法的封装。控件有自己的属性和方法。属性是指控件的特征。方法是指控件的一些简单而可见的功能
GTK中控件主要分为两类:容器控件,非容器控件。
- 容器控件:它可以容纳别的控件,我们可以理解为盒子,盒子拿来装东西。容器控件又分为两类,一类只能容纳一个控件,如窗口,按钮;另一类能容纳多个控件,如布局控件。
- 非容器控件:它不可以容纳别的控件,如标签、行编辑。
Put:
func (v *Fixed) Put(w IWidget, x, y int)
功能:固定布局容器添加控件
参数:
widget:要添加的控件
x, y:控件摆放位置的起点坐标
ShowAll:
func (v *Widget) ShowAll()
功能:显示所有的控件,如果窗口放入一个容器,这时,容器上的所有控件也会跟着显示。
package main
import (
"os"
"github.com/mattn/go-gtk/gtk"
)
func main() {
gtk.Init(&os.Args)
/*
gtk.Init(&os.Args):所有 GTK应用程序都要调用该函数,
而且必须在控件定义之前使用,它为我们设置一些缺省值
( 例如视觉和颜色 )映射这个函数将函数库初始化,设置
缺省的信号处理函数,并检查通过命令行传递给应用程序的
参数,自动完成一些必要的初始化工作。
*/
//--------------------------------------------------------
// 主窗口
//--------------------------------------------------------
window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL)
/*
gtk.NewWindow(gtk.WINDOW_TOPLEVEL):创建一个窗口并
返回这个窗口的控件指针。gtk.WINDOW_TOPLEVEL指明窗口
的类型为最上层的主窗口(则带边框的窗口),它最常用。
*/
window.SetPosition(gtk.WIN_POS_CENTER) //设置窗口居中显示
window.SetTitle("Minor Six Ren") //设置标题
window.SetSizeRequest(300, 200) //设置窗口的宽度和高度
//--------------------------------------------------------
// GtkFixed
//--------------------------------------------------------
layout := gtk.NewFixed() //创建固定布局
//--------------------------------------------------------
// GtkButton
//--------------------------------------------------------
b1 := gtk.NewButton() //新建按钮
b1.SetLabel("^_@") //设置内容
//b1.SetSizeRequest(100, 50) //设置按钮大小
b2 := gtk.NewButtonWithLabel("@_~") //新建按钮,同时设置内容
b2.SetSizeRequest(100, 50) //设置按钮大小
//--------------------------------------------------------
// 添加布局、添加容器
//--------------------------------------------------------
window.Add(layout) //把布局添加到主窗口中
layout.Put(b1, 0, 0) //设置按钮在容器的位置
layout.Move(b1, 50, 50) //移动按钮的位置,必须先put,再用move
layout.Put(b2, 50, 100)
window.ShowAll() //显示所有的控件
/*
window.Show():显示上一步创建的窗口控件。
window.ShowAll():显示所有的控件,如果窗口放入一个容器,这时,容器上的所有控件也会跟着显示
在这个简单例子里,所有事件都被忽略。用鼠标点击窗口右上角的“×”按钮也不能将窗口关闭。可通过任务管理器关闭。
*/
gtk.Main() //主事件循环,等待用户操作
/*
gtk.Main():它是在每个Gtk应用程序都要调用的
函数。程序运行停在这里等待事件(如键盘事件或
鼠标事件)的发生,等待用户来操作窗口。
*/
}
- 信号处理
“信号”在GTK中可以认为一种中断的标志
信号标识 | 触发条件 |
---|---|
clicked | 按下按钮时触发 |
pressed | 按下按钮时触发 |
released | 释放按钮时触发 |
destroy | 按关闭窗口按钮时触发 |
信号注册函数说明:
func (v *Widget) Connect(s string, f interface{}, datas ...interface{}) int
功能:信号注册
参数:
v: 信号发出者,可以认为我们操作的控件,如按下按钮,这个就为按钮指针
s:信号标志,如"pressed"
f:回调函数的名称,
datas:给回调函数传的参数,尽管是可变参数,但是只能传递一个参数,可变参数的目的为了让用户多个选择(可以传参,或者不传)
返回值:
注册函数的标志
package main
import (
"fmt"
"os"
"github.com/mattn/go-gtk/glib"
"github.com/mattn/go-gtk/gtk"
)
//按钮b1信号处理的回调函数
func HandleButton(ctx *glib.CallbackContext) {
arg := ctx.Data() //获取用户传递的参数,是空接口类型
p, ok := arg.(*int) //类型断言
if ok { //如果ok为true,说明类型断言正确
fmt.Println("*p = ", *p) //用户传递传递的参数为&tmp,是一个变量的地址
*p = 250 //操作指针所指向的内存
}
fmt.Println("按钮b1被按下")
//gtk.MainQuit() //关闭gtk程序
}
func main() {
gtk.Init(&os.Args)
window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL)
window.SetPosition(gtk.WIN_POS_CENTER)
window.SetTitle("GTK Go!")
window.SetSizeRequest(300, 200)
layout := gtk.NewFixed()
b1 := gtk.NewButton()
b1.SetLabel("按钮1")
b2 := gtk.NewButtonWithLabel("按钮2")
b2.SetSizeRequest(100, 50)
window.Add(layout)
layout.Put(b1, 0, 0)
layout.Move(b1, 50, 50) //移动按钮的位置,必须先put,再用move
layout.Put(b2, 50, 100)
//--------------------------------------------------------
// 信号处理
//--------------------------------------------------------
//按钮按下自动触发"pressed",自动调用HandleButton, 同时将 &tmp 传递给HandleButton
tmp := 10
b1.Connect("pressed", HandleButton, &tmp)
//回调函数为匿名函数,推荐写法
//按钮按下自动触发"pressed",自动调用匿名函数,
b2.Connect("pressed", func() {
fmt.Println("b2被按下")
fmt.Println("tmp = ", tmp)
}) //注意:}和)在同一行
window.ShowAll()
gtk.Main()
}
GTK+3
GTK+3:https://github.com/gotk3/gotk3
import (
"github.com/gotk3/gotk3/glib"
"github.com/gotk3/gotk3/gtk"
)
package main
import (
"fmt"
"github.com/gotk3/gotk3/glib"
"github.com/gotk3/gotk3/gtk"
"log"
"os"
)
//这部分是相同的
func main() {
const appId = "com.guidemo.example"
//每个gtk3程序都需要一步
app, err := gtk.ApplicationNew(appId, glib.APPLICATION_FLAGS_NONE)
/*
gtk.ApplicationNew()接受两个参数一个是 应用标识,其一般
使用你域名的倒序形式。另一个是GApplicationFlags,其为了
满足你对应用的特定需求。通常就像实例代码一样写
glib.APPLICATION_FLAGS_NONE就可以了。
*/
if err != nil {
log.Fatal("Could not create application.", err)
}
//为activate事件绑定函数, activate会在程序启动时触发,也就是app.Run()时
app.Connect("activate", func() {
onActivate(app)
} )
//运行gtkApplication
app.Run(os.Args)
}
func onActivate(application *gtk.Application) {
appWindow, err := gtk.ApplicationWindowNew(application) //创建window控件
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中的子控件。你可以修改,查看不同的效果
}
QT
QT: https://github.com/therecipe/qt
参考:https://github.com/therecipe/qt/wiki/Installation
- 安装
-
安装完整的Qt5在$HOME目录下
https://download.qt.io/official_releases/online_installers/ -
配置Qt的环境
# ~/.bash_profile
# therecipe/qt 需要的环境变量
export QT_DIR='/home/用户名/Qt5.11.1' # 安装Qt的目录
export QT_VERSION='5.11.1' # Qt的版本号
export QT_DEBUG=false # 是否启用debug
export QT_STUB=false # 内存低于2Gb或32位系统才需要设置true
# go1.10 cgo environments 使用go1.10时需要的设置
export CGO_CXXFLAGS_ALLOW=".*"
export CGO_LDFLAGS_ALLOW=".*"
export CGO_CFLAGS_ALLOW=".*"
- 补全依赖:
g++5.0+以及一些OpenGL的依赖
# Debian/Ubuntu的安装命令
sudo apt-get -y install build-essential libglu1-mesa-dev libpulse-dev libglib2.0-dev
# Fedora/RHEL/CentOS
sudo yum -y groupinstall "C Development Tools and Libraries"
sudo yum -y install mesa-libGLU-devel gstreamer-plugins-base pulseaudio-libs-devel glib2-devel
# openSUSE
sudo zypper -n install -t pattern devel_basis
# Arch Linux
sudo pacman -S base-devel
安装qt-tools:
go get -u -v github.com/therecipe/qt/cmd/...
安装bindings,记住远离sudo!!! (时间较久)
$GOPATH/bin/qtsetup
- 编译
参考:https://github.com/therecipe/qt/wiki/Available-Tools
不能直接使用go build,因为qt使用了moc技术(元对象编译器),对于一些Qt的扩展语法需要进行额外的处理
qtdeploy build [target] [path/to/your/project]
说明:
target是指定的目标平台,编译完成后的程序将可以在target指定的平台上运行。
如果也可以将target设为desktop,qtdeploy将会根据本地环境选择相对应的target。以下是部分可用的target选项:
desktop
windows
linux
android
android-emulator
ios
ios-simulator
sailfish
sailfish-emulator
rpi1
rpi2
rpi3