今天我们来讲讲自定义组件和它的构造函数。

在前面的文章里我们已经接触了好几个自定组件,这次的示例是一个自定义对话框,他有一个about按钮,点击按钮可以显示出Qt的信息或者用户输入的信息。这是效果图:





下面我们就来重点讲解自定义组件和它的构造函数吧。

构造函数的声明

先上代码:

  1. type MyDialog struct {
  2. widgets.QDialog
  3. _ func() `constructor:"init"`
  4. _ func(string) `signal:"showAbout"`
  5. _ func() `signal:"showAboutQt"`
  6. _ func(bool) `slot:"aboutClicked,auto"`
  7. _ func(string) `slot:"enableAboutButton,auto"`
  8. label *widgets.QLabel
  9. edit *widgets.QLineEdit
  10. testCheck *widgets.QCheckBox
  11. isDialogCheck *widgets.QCheckBox
  12. aboutButton *widgets.QPushButton
  13. closeButton *widgets.QPushButton
  14. }

构造函数用 “ _ func() `constructor:"init"` ”

来声明,目前只支持无参数的构造函数,以后会逐步扩展。之后我们需要实现一个名字是init的类方法,这是构造函数的实体。

qt的moc系统遇到派生自QObject及其派生类的类时,会自动生成一个New[type name]的函数(type name也会被Title处理),它会返回一个已经初始化的指向自定义类型实例的指针,这个函数的参数类型会根据最先继承的QObject或是其派生类的New[type name]而定,举个例子:

假设我们的类继承自QLineEdit,在qt里有NewQLineEdit(parent QWidget_ITF),那么我们这个类自动生成的New[type name]就会是New[type name](parent QWidget_ITF);

再举个例子,我们的组件继承自QWidget,它有NewQWidget(parent QWidget_ITF, fo core.Qt__WindowType),那么我们的类会自动生成New[type name](parent QWidget_ITF, fo core.Qt__WindowType)

我们实现的init会被New[type name]自动调用。不过这里有个问题,如果我想实现自己的New[type name]函数呢,比如需要加上自己的配置参数,其实也很简单,我们再定义一个New[type name]WithXXX然后在其中调用New[type name]即可,向下面这样:

  1. func NewYourTypeWithConfig(conf Config) *YourType {
  2. // 假设继承自QWidget
  3. obj := NewYourType(nil, 0)
  4. // 一些额外的初始化处理
  5. // 一般在init里进行界面的初始化,如果你的界面初始化依赖外部数据,那么可以不指定constructor,
  6. // 这样New[type name]就不会自动调用init,你可以在自定义函数里调用它。
  7. obj.conf = conf
  8. // obj.init()
  9. }

这就是构造函数的全貌了,接着我们来看看界面的初始化,也就是我们要实现的init函数:

  1. func (d *MyDialog) init() {
  2. d.label = widgets.NewQLabel2("About &Text:", d, 0)
  3. d.edit = widgets.NewQLineEdit(nil)
  4. // 将label和edit绑定
  5. d.label.SetBuddy(d.edit)
  6. d.testCheck = widgets.NewQCheckBox2("Test case", nil)
  7. // 选择显示自定义组件的About还是Qt的About
  8. d.isDialogCheck = widgets.NewQCheckBox2("Show &Dialog's about", nil)
  9. // 当用户输入要显示的内容时才可以点击
  10. d.aboutButton = widgets.NewQPushButton2("&About", nil)
  11. d.aboutButton.SetDefault(true)
  12. d.aboutButton.SetEnabled(false)
  13. d.closeButton = widgets.NewQPushButton2("&Close", nil)
  14. d.closeButton.ConnectClicked( func(_ bool) {
  15. d.Done(0)
  16. })
  17. d.edit.ConnectTextChanged(d.EnableAboutButton)
  18. d.aboutButton.ConnectClicked(d.aboutClicked)
  19. topLeftLayout := widgets.NewQHBoxLayout()
  20. topLeftLayout.AddWidget(d.label, 0, 0)
  21. topLeftLayout.AddWidget(d.edit, 0, 0)
  22. leftLayout := widgets.NewQVBoxLayout()
  23. leftLayout.AddLayout(topLeftLayout, 0)
  24. leftLayout.AddWidget(d.testCheck, 0, 0)
  25. leftLayout.AddWidget(d.isDialogCheck, 0, 0)
  26. rightLayout := widgets.NewQVBoxLayout()
  27. rightLayout.AddWidget(d.aboutButton, 0, 0)
  28. rightLayout.AddWidget(d.closeButton, 0, 0)
  29. rightLayout.AddStretch(0)
  30. mainLayout := widgets.NewQHBoxLayout()
  31. mainLayout.AddLayout(leftLayout, 0)
  32. mainLayout.AddLayout(rightLayout, 0)
  33. d.SetLayout(mainLayout)
  34. d.SetWindowTitle("about")
  35. }

代码也很简单,初始化widgets之后使用QBoxLayout进行布局,然后连接一下closeButton,使用QDialog::done退出dialog。

我们设置aboutButton初始为不可点击状态,直到有输入内容存在在改变它的状态,这一步由自动连接的enableAboutButton槽来完成;

然后是点击aboutButton时会检查isDialogCheck的值来确定弹出哪种对话框,这一步由aboutClicked槽来完成:

  1. func (d *MyDialog) aboutClicked(_ bool) {
  2. text := d.edit.Text()
  3. if d.isDialogCheck.IsChecked() {
  4. d.ShowAbout(text)
  5. } else {
  6. d.ShowAboutQt()
  7. }
  8. }
  9. func (d *MyDialog) enableAboutButton(text string) {
  10. if text != "" {
  11. d.aboutButton.SetEnabled(true)
  12. } else {
  13. d.aboutButton.SetEnabled(false)
  14. }
  15. }

然后就是主函数,将显示About对话框的信号和相应的处理函数连接,然后显示我们的组件:

  1. func main() {
  2. app := widgets.NewQApplication(len(os.Args), os.Args)
  3. dialog := NewMyDialog(nil, 0)
  4. // 显示About Qt
  5. dialog.ConnectShowAboutQt( func() {
  6. app.AboutQtDefault()
  7. })
  8. // 显示自定义内容的About
  9. dialog.ConnectShowAbout( func(text string) {
  10. widgets.NewQMessageBox(dialog).About(dialog, "About Dialog", text)
  11. })
  12. dialog.Show()
  13. app.Exec()
  14. }

显示About Qt时的效果:

怎么样,是不是很简单,下一篇文章里我们将结束对qt struct tags的探索,如果有任何疑问或者建议,欢迎在评论指出!

祝玩得愉快!

【golang-GUI开发】struct tags系统(二)qt的自定义组件和构造函数的更多相关文章

  1. 【golang-GUI开发】struct tags系统(一)

    我们已经介绍了qt的signal和slot,现在该讲讲它的struct tags系统了.qt拥有多种的struct tags,我们会去一一了解它们. 什么是struct tags? struct ta ...

  2. Java开发小技巧(二):自定义Maven依赖

    前言 我们在项目开发中经常会将一些通用的类.方法等内容进行打包,打造成我们自己的开发工具包,作为各个项目的依赖来使用. 一般的做法是将项目导出成Jar包,然后在其它项目中将其导入,看起来很轻松,但是存 ...

  3. vue2.0 之 douban (二)创建自定义组件tabbar

    1.大体布局 这个组件分为两部分:第一个是组件的外层容器,第二个是组件的子容器item,子组件里面又分为图片和文字组合.子组件有2个状态,一个默认灰色的状态,一个选中状态,我们来实现一下这个组件的布局 ...

  4. Android开发之自定义组件和接口回调

    说到自定义控件不得不提的就是接口回调,在Android开发中接口回调用的还是蛮多的.在这篇博客开始的时候呢,我想聊一下iOS的自定义控件.在iOS中自定义控件的思路是继承自UIView, 在UIVie ...

  5. 麒麟系统开发笔记(二):国产麒麟系统搭建Qt开发环境安装Qt5.12

    前言   开发国产应用,使用到银河麒麟V4,V10,本篇以V10记录,参照上一篇可安装V4.V7.V10三个版本,麒麟V4系自带了Qt,麒麟V10没有自带Qt,需要自己编译搭建环境.   银河麒麟V1 ...

  6. (dede)织梦系统二次开发笔记

    (dede)织梦系统二次开发记录 --soulsjie 一.模板常用文件说明 模板文件都在文件夹templets下,我们以默认模板(default)为例,对模板文件结构进行分析: 首页模板文件目录 \ ...

  7. 基于gin的golang web开发:路由二

    在基于gin的golang web开发:路由中我们介绍了Gin的路由和一些获取链接中参数的方法,本文继续介绍其他获取参数的方法. 文件上传 在web开发中文件上传是一个很常见的需求,下面我们来看一下基 ...

  8. Epicor系统二次开发

    Epicor系统二次开发 一.获取或修改界面EpiDataView的字段数据(Get EpiDataView data) C# EpiDataView edv = (EpiDataView)oTran ...

  9. 利用Qt开发跨平台APP(二)(iOS,使用Qt5.9,很详细,有截图)

    本文将手把手教你如何使用Qt编译出iOS应用程序. Qt是一个优秀的跨平台开发工具.我们利用Qt可以很方便地将一次编写的应用,多次编译到不同平台上,如Windows.Linux.MAC.Android ...

随机推荐

  1. artTemplate使用

    bower install artTemplate --save https://github.com/aui/artTemplate 快速上手 模板定义:   <div id="co ...

  2. JObject,JArray的基本操作

    引用:https://www.cnblogs.com/dacongge/p/6957074.html 1.JObject:基本的json对象 /// <summary> /// Gets ...

  3. iptables简单用法

    iptables -t 表名 <-A/I/D/R> 规则链名 [规则号] <-i/o 网卡名> -p 协议名 <-s 源IP/源子网> --sport 源端口 &l ...

  4. MVC项目加入WebApi

    一.NuGet搜索安装Microsoft.AspNet.WebApi,注意引用的版本依赖,因为是在完整的MVC项目上新增,在本地编译调试并没有报错,发布到IIS后却显示应用程序出错. 二.NuGet搜 ...

  5. 传统对象池&AB对象池

    前序: Q:为啥需要对象池? A: 游戏中大量出现或销毁对象时会反复的开堆和放堆,程序与内存之间交互过于频繁导致资源的大量浪费 Q: 对象池实现原理? A: 当子对象池没有物体的时候,它会和普通没加对 ...

  6. python基础自学 第三天

    变量的命名 01.标识符和关键字 标识符 标识符就是程序员定义的变量名.函数名. 标识符可以由字母,下划线,和数字组成. 不能以数字开头 不能与关键字重名 关键字 就是在python内部已经使用的标识 ...

  7. Java并发编程实战

    代码中比较容易出现bug的场景: 不一致的同步,直接调用Thread.run,未被释放的锁,空的同步块,双重检查加锁,在构造函数中启动一个线程,notify或notifyAll通知错误,Object. ...

  8. js 大厦之JavaScript事件

    1.js事件简介 事件(Event) 是 JavaScript 应用跳动的心脏 ,进行交互,使网页动起来.也是把所有东西粘在一起的胶水.当我们与浏览器中 Web 页面进行某些类型的交互时,事件就发生了 ...

  9. 字符编码那点事:快速理解ASCII、Unicode、GBK和UTF-8

    原作者:阮一峰(ruanyifeng.com),现重新整理发布,感谢原作者的无私分享. 1.引言 今天中午,我突然想搞清楚 Unicode 和 UTF-8 之间的关系,就开始查资料. 这个问题比我想象 ...

  10. 吴恩达机器学习笔记31-梯度检验(Gradient Checking)

    当我们对一个较为复杂的模型(例如神经网络)使用梯度下降算法时,可能会存在一些不容易察觉的错误,意味着,虽然代价看上去在不断减小,但最终的结果可能并不是最优解.为了避免这样的问题,我们采取一种叫做梯度的 ...