设为首页 收藏本站
查看: 1224|回复: 0

[经验分享] 【golang-GUI开发】qt之signal和slot(一)

[复制链接]

尚未签到

发表于 2018-9-20 13:35:39 | 显示全部楼层 |阅读模式
  想了很久,我决定还是先从signal和slot(信号槽)开始讲起。
  signal和slot大家一定不陌生,先看一段示例(选自文档):
  

>
{  

Q_OBJECT  

  
public:
  
     Counter() { m_value = 0; }
  

  
     int value() const { return m_value; }
  

  
public slots:
  
     void setValue(int value);
  

  
signals:
  
     void valueChanged(int newValue);
  

  
private:
  
     int m_value;
  
};
  

  使用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的自定义组件:
  

import "github.com/therecipe/qt/core"  

  
type MyWidget struct {
  
     core.QObject
  

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

  首先看到第四行,
  

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)"`  
}
  

  我们看到在signal的名字后面多了一个auto。
  这个auto是告诉qtmoc这个信号需要connect一个和signal tags里名字相同的成员方法,在这里成员函数的名字必须和tags里的相同,而不是经过strings.Title处理过的signal名字。
  然后我们定义并实现这个和DataChanged连接的成员函数:
  

func (a *Auto) dataChanged() {  fmt.Println(
"Data has been changed.")  
}
  

  这样你无需再显示调用ConnectDataChanged,DataChanged将自动和成员函数dataChanged连接。
  我们还看到有auto(this.QLabel.SetText)的写法,这是在自定义类型继承自其他QObject及其派生类时,可以自动连接基类的成员方法。
  this是指当前的对象;
  QLabel或是其他类型名表示继承的基类;
  SetText是基类的成员函数,它将与DataChanged信号相关联。这里写成setText也可以,因为在()里的函数名会被strings.Title处理。
  每当我们触发信号时:
  

widget := NewAuto(nil, 0)  

  
widget.DataChanged()
  
widget.ValueChanged(
"signal & slot")  

  相应的成员函数就会被调用,上面的代码会有如下反应:
  

// 因为DataChanged信号而被触发  
widget.dataChanged()
  

  
// 因为ValueChanged信号而被触发
  
widget.QLabel.SetText("signal & slot")
  
// 等价于
  
widget.SetText("signal & slot")
  

  有人会问,那可不可以用`signal:"dataChanged,auto(this.Myfunc)"`自己指定想要和信号connect的函数呢?
  答案是暂时不可以。目前auto只有上面两种用法,不过作者以及把实现自动连接成员变量的成员函数和自定义连接函数加入了开发计划中,相信不久之后就能用上这些功能了。
  以上就是qt中signal的具体用法,下一篇我们将会介绍slot的详细用法。
  如有疑问欢迎在评论中提出。
  参考:
  http://doc.qt.io/qt-5/signalsandslots.html



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-598927-1-1.html 上篇帖子: gocommand:一个跨平台的golang命令行执行package 下篇帖子: Golang 对接宝付、通联、富友金账户...填坑记
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表