标题是非常的哗众取宠了。这里主要是用来记录一些使用 Qt 的小经验。之前在工作中,会有一些关于 Qt 的经验总结,加之平时自己写一些小东西也有使用 Qt ,所以使用起来会有一些经验教训,聚集起来,姑且叫做 Effective Qt 了。随时想到会随时更新内容。(注:这里会有一些代码设计的思路,不存在绝对的正误,只是一种习惯)
- 避免在子控件中使用
parentWidget()
方法获取QWidget
指针强制转换为父控件指针,调用父对象方法。 在对子控件布局的时候,某些情况下实例化子控件时传递的父指针会被置空,例如对子控件设置一些特殊的窗口标志。 - 在
void paintEvent(QPaintEvent* e)
方法中的逻辑要避免出现间接调用update()
方法。 由于update()
方法与repaint()
机制不同,所以当出现上述情况,并不会直接爆栈,迅速发现问题。而是在某些会导致频繁重绘的操作下,程序异常卡顿,但是不涉及重绘的操作,程序又看起来没问题。 - 避免匿名空间内声明 Qt 类型、避免类外声明
static
Qt 类型。 避免 Qt 类型的某些内容比QCoreApplication
更早的初始化,导致一些数值异常。比如在更早的时机调用QStyle::dpiscaled()
,导致无法得到正确的系统DPI。 - 获取
connect()
方法的返回值,可以在 debug 时快速的发现自己的槽和信号没有正确的连接。 - 如果槽失效了,99% 是以下几种情况,剩下 1% 我没遇到过
- 类没有继承自 QObject
- 没有写 Q_OBJECT 宏
- 槽(信号)的定义没有写在 slots(signals) 下边
- connect 的时候写错了槽(信号)的名字或者参数
adjustSize()
、updateGeometry()
以及sizeHint()
是处理复杂界面布局变动的利器。 简单来说adjustSize()
是根据子控件调整自己的大小,updateGeometry()
是根据自己的大小和子控件的大小调整子控件的布局。在处理复杂布局时,还需要配合每一个控件本身的sizePolicy()
以及布局的sizeConstraint()
方可显示出Qt动态布局的威力updateGeometry()
并不是每次调用都一定会生效,有时候你需要QLayout::invalidate()
来辅助你更新布局。 Qt只会在它觉得需要重新更新的时候才更新(具体的判断可以参考源码,大意是说调过了setXXXSize()
这种方法以后,Qt才认为需要重新更新)。这个时候你可以选择拿到控件的QLayout
然后循环对每个布局调用QLayout::invalidate()
;在比较特殊的情况下你可以选择用setFixedSize(sizeHint())
这种奇怪的调用代替循环,当然请在你非常熟悉你在做什么的时候才去用这种方式代替循环。- 在发现有一个需求需要用到 Qt 的某些东西而又调不到时,请再三确认, Qt 有没有提供一些虚方法可以重写,大部分的需求都是可以通过某些虚方法完成,只有极少数需要将 Qt 内部的东西移出来用。
- 尽量使用
QLayout
来控制控件的位置,而不是套用一个又一个的QWidget
,因为永远不能预料到产品会把一个页面上的哪两个控件联系在一起,如果这些控件相隔了几个QWidget
,拿到它们的指针将是一件非常蛋疼的事 - 槽的命名应该以反映他被调用的时机,而不是他的功能。方便后边的人想在某个信号发送的时候,快速的找到一个准确的槽位置,而不会同一个信号在同一个类里绑定了多个槽
未完待续……