Effective Qt

标题是非常的哗众取宠了。这里主要是用来记录一些使用 Qt 的小经验。之前在工作中,会有一些关于 Qt 的经验总结,加之平时自己写一些小东西也有使用 Qt ,所以使用起来会有一些经验教训,聚集起来,姑且叫做 Effective Qt 了。随时想到会随时更新内容。(注:这里会有一些代码设计的思路,不存在绝对的正误,只是一种习惯

  1. 避免在子控件中使用 parentWidget() 方法获取 QWidget 指针强制转换为父控件指针,调用父对象方法。

    在对子控件布局的时候,某些情况下实例化子控件时传递的父指针会被置空,例如对子控件设置一些特殊的窗口标志。

  2. void paintEvent(QPaintEvent* e) 方法中的逻辑要避免出现间接调用 update() 方法。

    由于 update() 方法与 repaint() 机制不同,所以当出现上述情况,并不会直接爆栈,迅速发现问题。而是在某些会导致频繁重绘的操作下,程序异常卡顿,但是不涉及重绘的操作,程序又看起来没问题。

  3. 避免匿名空间内声明 Qt 类型、避免类外声明static Qt 类型。

    避免 Qt 类型的某些内容比 QCoreApplication 更早的初始化,导致一些数值异常。比如在更早的时机调用 QStyle::dpiscaled(),导致无法得到正确的系统DPI。

  4. 获取 connect() 方法的返回值,可以在 debug 时快速的发现自己的槽和信号没有正确的连接。
  5. 如果槽失效了,99% 是以下几种情况,剩下 1% 我没遇到过
    1. 类没有继承自 QObject
    2. 没有写 Q_OBJECT 宏
    3. 槽(信号)的定义没有写在 slots(signals) 下边
    4. connect 的时候写错了槽(信号)的名字或者参数
  6. adjustSize()updateGeometry()以及sizeHint()是处理复杂界面布局变动的利器。

    简单来说 adjustSize() 是根据子控件调整自己的大小,updateGeometry() 是根据自己的大小和子控件的大小调整子控件的布局。在处理复杂布局时,还需要配合每一个控件本身的 sizePolicy() 以及布局的 sizeConstraint() 方可显示出Qt动态布局的威力

  7. updateGeometry() 并不是每次调用都一定会生效,有时候你需要 QLayout::invalidate() 来辅助你更新布局。

    Qt只会在它觉得需要重新更新的时候才更新(具体的判断可以参考源码,大意是说调过了 setXXXSize() 这种方法以后,Qt才认为需要重新更新)。这个时候你可以选择拿到控件的 QLayout 然后循环对每个布局调用 QLayout::invalidate() ;在比较特殊的情况下你可以选择用 setFixedSize(sizeHint()) 这种奇怪的调用代替循环,当然请在你非常熟悉你在做什么的时候才去用这种方式代替循环。

  8. 在发现有一个需求需要用到 Qt 的某些东西而又调不到时,请再三确认, Qt 有没有提供一些虚方法可以重写,大部分的需求都是可以通过某些虚方法完成,只有极少数需要将 Qt 内部的东西移出来用。
  9. 尽量使用 QLayout 来控制控件的位置,而不是套用一个又一个的 QWidget ,因为永远不能预料到产品会把一个页面上的哪两个控件联系在一起,如果这些控件相隔了几个 QWidget ,拿到它们的指针将是一件非常蛋疼的事
  10. 槽的命名应该以反映他被调用的时机,而不是他的功能。方便后边的人想在某个信号发送的时候,快速的找到一个准确的槽位置,而不会同一个信号在同一个类里绑定了多个槽

未完待续……