① 关于“独立的窗口句柄” —— 部分正确,但致命

  • 你的理解:每个QWidget都有自己的HWND(或X11 Window)。

  • 底层真相:确实如此。只要你设置setAttribute(Qt::WA_NativeWindow)或让它成为顶层窗口(无父窗口),Qt会为它向操作系统申请一个独立的内核对象Windows下是HWND,Linux下是XID)。

  • 致命在哪:操作系统为每个窗口在内核非分页池中分配内存,且GDI句柄总数全局有限(Win10/11默认上限约65536个)。3000个窗口会瞬间吃掉近一半的系统句柄资源,导致其他软件(甚至任务管理器)绘制异常。


② 关于“独立的事件循环” —— 完全错误(这是最大的误解)

  • 你的理解:每个控件拥有自己的事件循环(QEventLoop)来处理自己的消息。

  • 底层真相(极重要)

    • 在Qt中,所有QWidget必须且只能存活在GUI主线程(主线程)

    • 操作系统层:Windows的消息队列(GetMessage/DispatchMessage)是线程级别的,而不是窗口级别的。整个进程的主线程只有一个消息队列。

    • Qt层:整个应用程序只有一个主事件循环(QApplication::exec())。当鼠标点击窗口A时,操作系统把WM_LBUTTONDOWN投递到主线程的消息队列,Qt的QWindowsGuiEventDispatcher取出这个消息,根据HWND找到对应的QWidget对象指针,然后调用该对象的event()函数。

  • 类比:操作系统是“总收发室”,所有窗口的信件(消息)都送到同一个收发室(主线程消息队列),收发员(Qt主循环)再按门牌号(HWND)分发给各家(窗口)。不存在每家自己设一个独立的收发室(独立循环)

  • 如果你强行在子线程创建QWidget并跑QEventLoop,Qt会在create()系统调用时断言失败(ASSERT: "QWidget::create: Widgets must be created in the GUI thread"),程序直接崩溃。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐