分享
  1. 首页
  2. 文章

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

apocelipes · · 1153 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

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

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


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

构造函数的声明

先上代码:

type MyDialog struct {
 widgets.QDialog
 
 _ func() `constructor:"init"`
 
 _ func(string) `signal:"showAbout"`
 _ func() `signal:"showAboutQt"`
 
 _ func(bool) `slot:"aboutClicked,auto"`
 _ func(string) `slot:"enableAboutButton,auto"`
 
 label *widgets.QLabel
 edit *widgets.QLineEdit
 testCheck *widgets.QCheckBox
 isDialogCheck *widgets.QCheckBox
 aboutButton *widgets.QPushButton
 closeButton *widgets.QPushButton
}

构造函数用 " _ 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]即可,向下面这样:

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

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

func (d *MyDialog) init() {
 d.label = widgets.NewQLabel2("About &Text:", d, 0)
 d.edit = widgets.NewQLineEdit(nil)
 // 将label和edit绑定
 d.label.SetBuddy(d.edit)
 
 d.testCheck = widgets.NewQCheckBox2("Test case", nil)
 // 选择显示自定义组件的About还是Qt的About
 d.isDialogCheck = widgets.NewQCheckBox2("Show &Dialog's about", nil)
 // 当用户输入要显示的内容时才可以点击
 d.aboutButton = widgets.NewQPushButton2("&About", nil)
 d.aboutButton.SetDefault(true)
 d.aboutButton.SetEnabled(false)
 
 d.closeButton = widgets.NewQPushButton2("&Close", nil)
 d.closeButton.ConnectClicked( func(_ bool) {
 d.Done(0)
 })
 
 d.edit.ConnectTextChanged(d.EnableAboutButton)
 d.aboutButton.ConnectClicked(d.aboutClicked)
 
 topLeftLayout := widgets.NewQHBoxLayout()
 topLeftLayout.AddWidget(d.label, 0, 0)
 topLeftLayout.AddWidget(d.edit, 0, 0)
 
 leftLayout := widgets.NewQVBoxLayout()
 leftLayout.AddLayout(topLeftLayout, 0)
 leftLayout.AddWidget(d.testCheck, 0, 0)
 leftLayout.AddWidget(d.isDialogCheck, 0, 0)
 
 rightLayout := widgets.NewQVBoxLayout()
 rightLayout.AddWidget(d.aboutButton, 0, 0)
 rightLayout.AddWidget(d.closeButton, 0, 0)
 rightLayout.AddStretch(0)
 
 mainLayout := widgets.NewQHBoxLayout()
 mainLayout.AddLayout(leftLayout, 0)
 mainLayout.AddLayout(rightLayout, 0)
 d.SetLayout(mainLayout)
 
 d.SetWindowTitle("about")
}

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

我们设置aboutButton初始为不可点击状态,直到有输入内容存在在改变它的状态,这一步由自动连接的enableAboutButton槽来完成;
然后是点击aboutButton时会检查isDialogCheck的值来确定弹出哪种对话框,这一步由aboutClicked槽来完成:

func (d *MyDialog) aboutClicked(_ bool) {
 text := d.edit.Text()
 
 if d.isDialogCheck.IsChecked() {
 d.ShowAbout(text)
 } else {
 d.ShowAboutQt()
 }
}
func (d *MyDialog) enableAboutButton(text string) {
 if text != "" {
 d.aboutButton.SetEnabled(true)
 } else {
 d.aboutButton.SetEnabled(false)
 }
}

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

func main() {
 app := widgets.NewQApplication(len(os.Args), os.Args)
 
 dialog := NewMyDialog(nil, 0)
 // 显示About Qt
 dialog.ConnectShowAboutQt( func() {
 app.AboutQtDefault()
 })
 // 显示自定义内容的About
 dialog.ConnectShowAbout( func(text string) {
 widgets.NewQMessageBox(dialog).About(dialog, "About Dialog", text)
 })
 
 dialog.Show()
 
 app.Exec()
}

显示About Qt时的效果:

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


有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
1153 次点击
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏