设为首页 加入收藏

TOP

【golang-GUI开发】qt之signal和slot(一)(一)
2018-10-19 15:51:28 】 浏览:135
Tags:golang-GUI 开发 signal slot

想了很久,我决定还是先从signal和slot(信号槽)开始讲起。

signal和slot大家一定不陌生,先看一段示例(选自文档):

 1 class Counter : public QObject
 2 {
 3     Q_OBJECT
 4 
 5 public:
 6     Counter() { m_value = 0; }
 7 
 8     int value() const { return m_value; }
 9 
10 public slots:
11     void setValue(int value);
12 
13 signals:
14     void valueChanged(int newValue);
15 
16 private:
17     int m_value;
18 };

使用signal和slot的类必须包含Q_OBJECT宏,声明slot需要使用public/private/protected slots:,signal则需要signals:。

这些其实都是宏,它们会指示moc做相应的代码生成,这样Qt程序才可以发送信号,并让slot与signal相连接。

可是golang并没有宏,那么在qt里我们要怎么做呢?

信号----Signal

1. 信号----signal的定义

想要自定义signals,我们需要用到golang的一个简单特性--struct tags。

tags被广泛的用于golang的世界里,从标准库encoding/json到广泛使用的orm(xorm,gorm),tags的身影无处不在。tags之所以应用广泛是因为它可以被reflect取到,

依赖于强大的reflect包,可以通过tags来实现各种各样的功能,其中就包括Qt的moc扩展。

下面我们看一下一个带有两个自定义signal的自定义组件:

1 import "github.com/therecipe/qt/core"
2 
3 type MyWidget struct {
4     core.QObject
5     
6     _ func() `signal:"dataChanged"`
7     _ func(int) `signal:"valueChanged"`
8 }

首先看到第四行,

core.QObject

所有需要自定义slot和signal的类都必须是core.QObject的派生类型,如果不是直接继承自QObject,那么直接继承的类型必须要直接或间接的继承自QObject。

同时要注意,不要用*core.QObject的形式,这会导致qtmoc忽略这个类,最终不能处理moc扩展引发问题

_ func() `signal:"dataChanged"`
_ func(int) `signal:"valueChanged"`

我们定义了两个signal,第一个不带任何参数,第二个带有一个int类型参数。

qtmoc会把tags的内容用strings.Title做处理,也就是说dataChanged会变成DataChanged,这就是我们定义的信号的名字。

接着qtmoc会根据这个名字以及tags所在成员的类型生成自定义控件类的三个成员方法:Connect[signal name],Disconnect[signal name],[signal name],

在本例中就是:ConnectDataChanged,DisconnectDataChanged和Datachanged。

 

2. 信号----signal的连接

想要和signal连接,需要用到前面提到的Connect[signal name]函数。

qtmoc会根据signal的类型来生成Connect函数,这里的ConnectDataChanged的原型就是func ConnectDataChanged( f func() )。

需要连接这个signal时,调用它并把signal处理函数传递为参数即可

func sample() {
    fmt.Println("Data has been changed.")
}

widget := NewMyWidget(nil) // 这里是创建我们的自定义组件,后面的文章我们会重点讲解
// Qt5中与signal相连的可以是任何函数,在qt里也是一样,所以我们用一个外部函数来处理signal,在实际开发中还是推荐用类的成员方法或者slot进行处理
widget.ConnectDataChanged(sample)

这里我们把sample和信号DataChanged相连,每次触发这个信号时都会打印出“Data has been changed.”这句信息。

如果想要取消和某个信号的连接,需要使用Disconnect[signal name]函数,它不带参数,调用它意味着取消signal与上一次使用Connect[signal name]时作为参数的函数的连接。

widget.DisconnectDataChanged()
// 我们取消了sample函数与DataChanged的连接

 

3. 信号----signal的触发

C++中要触发一个信号,只需要如下代码:

emit DataChanged()
emit ValueChanged(value)

emit?在C++和golang里都没见过的语法。。。。。。没错,这也是Qt的moc扩展。

还记得我们说道qtmoc会根据signal tags生成三个成员方法吗,ConnectDataChanged,DisconnectDataChanged,DataChanged

第三个函数就是我们用来触发信号的。

信号触发函数用来代替emit,它自身是一个根据signal tags前的类型生成的函数,所以MyWidget.DataChanged的类型是func f();而ValueChanged函数的类型就是func f(value int)。

注意,与Qt一样,signal不可以拥有返回值

下面是触发信号的示例:

// 触发DataChanged信号
widget.DataChanged()

value := 5
// 触发ValueChanged信号并传递参数
widget.ValueChanged(1)
widget.ValueChanged(100)
widget.ValueChanged(value)

触发信号之后,之前与之相连的函数就会被调用了。

 

4. 信号----signal的自动连接

如果自定义的signal比较多,那么一个个的调用Connect[signal name]不仅麻烦低效,还会带来维护上的困难,所以qt提供了自动连接的功能。

先看代码:

import (
    "github,com/therecipe/qt/widgets"
)

type Auto struct {
    widgets.QLabel

    _ func() `signal:"dataChanged,auto"`
    _ func(string) `signal:"valueChanged,auto(this.QLabel.SetText)"`
}

我们看到

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇groupcache源码解析-概览 下一篇牛客网_Go语言相关练习_选择题(1..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目