当前位置: 首页 > news >正文

Qt 未说明的特性和要注意的点(持续更新)

  • 从 Qt5.6 开始 Qt 新增了一个未公开的 qmake 变量 COPIES,通过它我们可以快速实现额外文件的部署:

    # 新增一个复制任务 #
    COPIES += myDocumentation
    # 要复制的文件列表 #
    myDocumentation.files = $$files(text/docs/*.txt)
    # 要复制到的目标目录 #
    myDocumentation.path = $$OUT_PWD/documentation
    # 可选项,指定源文件要截断掉的基本路径 (疑似存在 BUG,无法正确工作) #
    myDocumentation.base = $$PWD/text/docs
    

    详情可参见 file_copies.prf 文件。

  • Qt5.15.2 下, 当为 QLabel 设置 margin 或 padding 时, 需要明确将 Indent 设置为 0, 否则文本的位置将会有些偏移。

    参见:

    https://doc.qt.io/qt-5/qlabel.html#indent-prop

    If indent is negative, or if no indent has been set, the label computes the effective indent as follows: If frameWidth() is 0, the effective indent becomes 0. If frameWidth() is greater than 0, the effective indent becomes half the width of the "x" character of the widget's current font().

    By default, the indent is -1, meaning that an effective indent is calculating in the manner described above.

    https://doc.qt.io/qt-5/stylesheet-reference.html#QFrame

    QFrame Supports the box model.Since 4.3, setting a stylesheet on a QLabel automatically sets the QFrame::frameStyle property to QFrame::StyledPanel.See Customizing QFrame for an example.
  • Qt5.15.2 下, 当需要为 QLabel 设置单项边框时, 需要先对所有的边框属性进行设置或设置 background 属性, 否则单项边框设置不起效。例如:

    border: none; or background-color: transparent;
    border-bottom: 1px solid #F1F1F1;
    
  • 可使用如下方式在 QSS 中设置小部件的 alignment 属性:

    label.setStyleSheet("qproperty-alignment: AlignCenter;");  // 单个值
    label.setStyleSheet("qproperty-alignment: 'AlignBottom | AlignRight';");  // 多个值
    
  • QSS 下的 add-line 属性代表 QScrollBar 等组件的向右滚动或向下滚动按钮。同理, sub-line 代表向左滚动或向上滚动按钮:

    QScrollBar::add-line:horizontal {background: blue;width: 16px;subcontrol-position: right;subcontrol-origin: margin;border: 2px solid black;
    }QScrollBar::sub-line:horizontal {background: magenta;width: 16px;subcontrol-position: top right;subcontrol-origin: margin;border: 2px solid black;position: absolute;right: 20px;
    }
    

    add-line

  • QSS 下的 add-page 属性代表 QScrollBar/QSlider 等组件滑块右侧或下侧的背景色。同理, sub-page 代表向滑块左侧或上侧的背景色:

    QSlider::sub-page:horizontal{background:rgba(80,166,234,1);
    }
    

    sub-page

  • 使用函数对象作为槽函数的问题在于:

    1. 开发者很容易误以为, 函数对象代码所在的类对象销毁时会自动断开连接,但实际上除非发送者销毁或手动断开连接, 否则连接不会自动断开。
    2. 如果函数中依赖其它对象, 那么可能需要处理依赖对象被销毁的情况或需要做到依赖对象被销毁时自动断开连接。
  • QSS 选择器之间可通过 ',' 分隔以同时匹配多个类型:

     #stkwgMainPanel QLabel, #stkwgMainPanel QPushButton {color: #212429;font-weight: 400;}
    
  • QLayout::addWidget 会变更 widget 的 parent 为 layout 所绑定的 widget。或者说,任何添加到布局上的小部件的 parent 都会被变更为持有布局对象父小部件。而 QLayout::removeWidget 不会将 widget 的 parent 置为空。

  • 一但 widget 被添加到布局上,那么它将会被设置 Qt::WA_LaidOut 属性,此后该属性永远不会被移除。

  • 经测试,QMutex 在 windows 下是 公平锁

  • QWaitCondition::wake** 仅仅是唤醒等待的线程,并不会让被唤醒的线程获得锁,被唤醒的线程还需要等待持锁线程释放锁才行。

  • QThread 在退出时不会清空其事件队列, 这会导致 QThread 在下次启动时触发先前事件队列中的事件, 有时这不是我们所希望的。验证代码:

    int main(int argc, char *argv[])
    {QCoreApplication a(argc, argv);qDebug() << QThread::currentThreadId() << "main thread";QThread* t = new QThread();t->moveToThread(t);QObject::connect(t, &QThread::finished, t, [t]() {QMetaObject::invokeMethod(t, []() {qDebug() << QThread::currentThreadId() << "finished then invokeMethod called";},Qt::QueuedConnection);} );t->start();QMetaObject::invokeMethod(t, []() {qDebug() << QThread::currentThreadId() << "invokeMethod0 called";},Qt::QueuedConnection);QThread::msleep(500);QMetaObject::invokeMethod(t, []() {qDebug() << QThread::currentThreadId() << "invokeMethod1 called";},Qt::QueuedConnection);t->quit();/* 如果启用下方代码, 那么将输出 invokeMethod1 called; finished then invokeMethod called* 这说明线程在退出时不会清空事件队列! 队列中的事件将在下次启动时触发! */
    //    QThread::msleep(500);
    //    t->start();QThread::msleep(500);delete t;return 0;
    }
    
  • 对于 Qt::QueuedConnection 类型的信号槽连接, 当发送者被释放时, 已发出的信号 (posted events) 不会被移除, 而是仍然会触发槽函数并且 sender() 返回为空。同理,disconnect 方法也不会移除已发出的信号,而如果是接收者被释放的话,那么已发出的信号会被移除。验证代码:

        SenderObj *obj = new SenderObj();connect(obj, &SenderObj::sig, this, &Widget::onSig_direct, Qt::DirectConnection);connect(obj, &SenderObj::sig, this, &Widget::onSig_Queue, Qt::QueuedConnection);qDebug() << "call send";obj->send();qDebug() << "call send over";delete obj;  // 启用该行后 onSig_Queue 仍然触发, 证实 sender 释放时已投递的事件不会移除, sender() 为空/* 输出:call sendvoid Widget::onSig_direct() sender: SenderObj(0x192ac08)call send overvirtual SenderObj::~SenderObj()void Widget::onSig_Queue() sender: QObject(0x0)*/// delete this;  // 启用该行后 onSig_Queue 将不再触发, 证实对象在释放后其 pending posted events 确实会移除/* 输出:call sendvoid Widget::onSig_direct() sender: SenderObj(0x16eec60)call send over*/// obj->disconnect(this);  // 启用该行后 onSig_Queue 仍然触发, 证实调用 disconnect 时已投递的事件不会移除, sender() 为空/* 输出:call sendvoid Widget::onSig_direct() sender: SenderObj(0x32bdf78)call send overvoid Widget::onSig_Queue() sender: QObject(0x0)*/
    
  • QTcpServer::newConnection 信号触发时, 我们必须在 QTcpServer 对象的所在线程上立即调用 QTcpServer::nextPendingConnection , 否则极端情况下其返回的 QTcpSocket 对象可能是已断开连接的。这是因为 Qt 并未对 pendingConnections 队列中的 QTcpSocket 对象状态做任何保证, 参见 Qt 源码实现:

    void QTcpServer::incomingConnection(qintptr socketDescriptor)
    {QTcpSocket *socket = new QTcpSocket(this);socket->setSocketDescriptor(socketDescriptor);addPendingConnection(socket);
    }void QTcpServer::addPendingConnection(QTcpSocket* socket)
    {d_func()->pendingConnections.append(socket);
    }QTcpSocket *QTcpServer::nextPendingConnection()
    {Q_D(QTcpServer);if (d->pendingConnections.isEmpty())return nullptr;if (!d->socketEngine) {qWarning("QTcpServer::nextPendingConnection() called while not listening");} else if (!d->socketEngine->isReadNotificationEnabled()) {d->socketEngine->setReadNotificationEnabled(true);}return d->pendingConnections.takeFirst();
    }
    

    或者,我们在 QTcpServer 对象的所在线程上调用 QTcpServer::nextPendingConnection 后先对 QTcpSocket 对象的状态做检查。

  • Qt 的 Socket 对象必须在其所属线程关闭之前释放完毕,否则 Socket 对象内部可能因所属线程不存在而出错。

  • QWidget 的 isHiddenisVisible 方法并不相等:

    inline bool QWidget::isVisible() const
    { return testAttribute(Qt::WA_WState_Visible); }
    inline bool QWidget::isHidden() const
    { return testAttribute(Qt::WA_WState_Hidden); }
    

    这一点在一些场景下尤为重要。比如在编写布局管理器时, 我们使用 QLayoutItem::isEmpty (call QWidget::isHidden) 来判断小部件是否是可见,而不是直接调用 QWidget::isVisible 来判断。

  • 对于 QIODevice::write(const QByteArray &byteArray) 方法,如果 byteArray 中存储的数据包含 0,那么写入将停止。为了应对该问题,应使用 write(byteArray.data(), byteArray.size()) 写法。

  • qmake 函数 qtConfig 用于检查指定的 Qt 特性是否启用。其在 Qt 安装目录下的编译器/mkspecs/features/qt_functions.prf 文件中定义(至少 Qt5.6.3 之后的版本,之前的版本中不存在该函数)。此外该文件中还定义了其它实用函数可用于构建系统的配置。

  • QWidget::size 返回的是小部件整体大小,包含 content、padding、border、margin。

  • qss 的 min-width 以及 max-height 等属性设置的是小部件的 contentSize。


--- 2024-‎5-‎23
http://www.jsqmd.com/news/120364/

相关文章:

  • Bugku--花点流量听听歌、图穷匕见、隐写2、look、、铁子,来一道
  • Java毕设项目:基于springboot的物业报修系统的设计与实现(源码+文档,讲解、调试运行,定制等)
  • 2025年儿童羽绒服十大名牌排名:宝妈选购指南与品牌解析 - 品牌测评鉴赏家
  • Java毕设项目:基于springboot的幼儿园管理系统的设计与实现(源码+文档,讲解、调试运行,定制等)
  • 洛谷 P4314
  • 【计算机毕业设计案例】基于springboot的物业报修系统的设计与实现线上化的报修管理平台(程序+文档+讲解+定制)
  • 2025年上海办公室装修全景指南:从规划布局到服务商甄选的权威解析 - 小白条111
  • 【毕业设计】基于springboot的影视同人创作与分享平台系统(源码+文档+远程调试,全bao定制等)
  • 2025年儿童鞋服口碑榜单出炉!从运动机能到时尚穿搭,这十大品牌承包孩子的成长衣橱 - 品牌测评鉴赏家
  • 用 .NET MAUI 10 + VS Copilot 从 0 开发一个签到 App(八)复盘 —— Copilot 在 MAUI 项目中的真实边界
  • 【计算机毕业设计案例】基于springboot的幼儿园管理系统的设计与实现活动信息、课程信息、菜谱信息(程序+文档+讲解+定制)
  • Java毕设项目:基于springboot的在线招标系统的设计与实现(源码+文档,讲解、调试运行,定制等)
  • 宝妈宝爸必看!超赞儿童鞋服家居服品牌大赏 - 品牌测评鉴赏家
  • AI原生应用开发效率提升:这些工具让你事半功倍
  • 【课程设计/毕业设计】基于springboot的影视同人创作与分享平台系统构建 “创作发布 - 社区互动 - 版权管理” 的一体化平台【附源码、数据库、万字文档】
  • 为什么基于selenium实现浏览器自动化操作的时候,建议搭配webdriverManager使用。
  • Java毕设项目:基于springboot的社区团购系统的设计与实现(源码+文档,讲解、调试运行,定制等)
  • 【计算机毕业设计案例】基于springboot的在线招标系统的设计与实现构建 “招标管理 - 投标响应 - 开标评标 - 结果公示 - 档案归档” 一体化平台(程序+文档+讲解+定制)
  • 【毕业设计】基于springboot的社区团购系统的设计与实现(源码+文档+远程调试,全bao定制等)
  • 计算机Java毕设实战-基于springboot的幼儿园管理系统的设计与实现基于Springboot+vue的幼儿园管理系统设计与实现【完整源码+LW+部署说明+演示视频,全bao一条龙等】
  • 解码QPixmap 图片自适应控件缩放与圆角处理
  • 2025年中国十大童装品牌盘点:品质与时尚兼具,守护孩子童年风采 - 品牌测评鉴赏家
  • Java计算机毕设之基于springboot的社区团购系统的设计与实现基于springboot的社区生鲜团购系统(完整前后端代码+说明文档+LW,调试定制等)
  • 小童童装选购全攻略:从品牌到穿搭,新手爸妈必看指南 - 品牌测评鉴赏家
  • 【毕业设计】基于springboot的物业报修系统的设计与实现(源码+文档+远程调试,全bao定制等)
  • 计算机Java毕设实战-基于SpringBoot与Vue的在线招投标系统设计与实现基于springboot的在线招标系统的设计与实现【完整源码+LW+部署说明+演示视频,全bao一条龙等】
  • 堆排序和topk问题
  • 【计算机毕业设计案例】基于SpringBoot的社区线上团购系统设计与实现基于springboot的社区团购系统的设计与实现(程序+文档+讲解+定制)
  • 2025年终优选:0-16岁儿童鞋服宝藏品牌大公开 - 品牌测评鉴赏家
  • 【MTSP问题】基于螳螂虾算法MShOA求解单仓库多旅行商问题附Matlab代码