部件提升
Qt中的部件提升非常有用,我们可以在现有的部件基础之上增加一些我们自己个性化的需求。然而由于Go语言的特性,和therecipe/qt的完成度,对于使用部件提升需要一些技巧。
LED-需求描述
假定我们希望实现一个简单的LED显示部件,这个部件有一个属性State
,通过设置布尔值可以显示红和绿两种状态。
这个功能有多种方式可以实现,我们可以通过扩展QLabel
,并通过调用setPicture
或setPixmap
来实现,也可以扩展QWidget
,并通过重写paintEvent
来实现,这里我们使用后者。
手撸的实现方式
让我们先手撸一下,完整代码如下:
package main
import (
"os"
"github.com/therecipe/qt/core"
"github.com/therecipe/qt/gui"
"github.com/therecipe/qt/widgets"
)
type Led struct {
*widgets.QWidget
State bool
}
func NewLed(p widgets.QWidget_ITF) *Led {
var par *widgets.QWidget
if p != nil {
par = p.QWidget_PTR()
}
w := &Led{QWidget: widgets.NewQWidget(par, 0)}
w.State = true
w.ConnectPaintEvent(w.paintEvent)
return w
}
func (c *Led) paintEvent(evt *gui.QPaintEvent) {
var color *gui.QColor
if c.State == false {
color = gui.NewQColor3(255, 0, 0, 128)
} else {
color = gui.NewQColor3(0, 255, 0, 128)
}
painter := gui.NewQPainter2(c)
painter.SetBrush(gui.NewQBrush3(color, core.Qt__SolidPattern))
painter.DrawEllipse3(0, 0, c.Width()-1, c.Height()-1)
}
func main() {
widgets.NewQApplication(len(os.Args), os.Args)
window := widgets.NewQDialog(nil, 0)
window.Resize2(400, 200)
gridLayout := widgets.NewQGridLayout(window)
led1 := NewLed(window)
gridLayout.AddWidget(led1)
led2 := NewLed(window)
led2.State = false
gridLayout.AddWidget2(led2, 0, 1, 0)
window.Show()
widgets.QApplication_Exec()
}
运行效果如图:
可以看到,和C++或者pyQt代码上有几点不同。首先,由于Go语言没有继承,需要利用结构体的组合来实现类似继承的功能,因此在创建自定义部件类型的时候有一些差异。其次,既然继承不存在了,那么重写自然也不存在,因此,新的paintEvent
需要通过ConnectPaintEvent
显式地指定。
使用Designer
我们会发现,手撸起来还是挺烦的,尤其是窗口复杂了之后,那么如何用Designer来简化操作呢?(当你看完这节你会发现,就算用了Designer也一样烦……)
首先,用Designer画一个窗口,放两个QWidget
,右键点击部件,选择提升为
,打开对话框,咱们还叫LED
。
之后在工程目录下新建一个ui文件夹,将窗口保存到ui文件夹内(假装叫lesson7.ui
)。之后运行qtdeploy
(会失败)或者qtrcc
。此时可以看到在ui目录下多了一个uic_lesson7.go
。之后我们需要将ui文件夹改名,否则再次运行qtdeploy
时,我们对uic_lesson7.go
中做的所有改动都会被覆盖。假设我们更名为myui。我们将之前代码中关于led的部分复制到uic_lesson7.go
中。并修改Dialog
结构体定义和SetupUI
函数中关于LED
的部分,将之前的widgets.
去掉。修改main.go
,如下:
package main
import (
"os"
ui "test/myui"
"github.com/therecipe/qt/widgets"
)
func main() {
widgets.NewQApplication(len(os.Args), os.Args)
window := ui.NewDialog(nil)
window.Show()
window.Led2.State = false
widgets.QApplication_Exec()
}
显示效果也是一样的。
通过Designer可以一定程度上简化界面代码编写,但是涉及到提升的这部分,由于therecipe/qt转换ui的过程中,并没有区分自定义部件和原生部件,因此还需要开发者对生成的uic文件进行修改。关于uic生成部分代码见github中的rcc
函数,感兴趣的同学也可以自行修改。