GUI編程
互聯網上已經涌現出不少成熟、好用的第三方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.選擇主窗口,根據需要設置窗口的相應屬性
2. 選擇布局容器
3. 根據需要選擇相應的控件,根據需要設置控件的相應屬性
- 環境搭建(windows)
- 下載安裝msys2
- 安裝所需軟件
安裝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
不能直接使用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