Qt窗口被外部(非Qt內部機制)強制銷毀,第二次再重復使用不顯示

在Qt開發中,窗口被外部(非Qt內部機制)強制銷毀

警告信息

External WM_DESTROY received for QWidgetWindow(0x108b8cbdb10, name="xxxxx") , parent: QWindow(0x0) , transient parent: QWindow(0x0)

使用場景

代碼結構如下:

  1. 自定義對話框類(CustomWaitDialog):
    靜態函數getStaticDialog():返回靜態對話框指針(如果為空則創建)
    靜態函數waitShow(QWidget *parent):
    • 獲取靜態對話框指針
    • 設置父對象為傳入的parent,并設置窗口標志(使用dialog->windowFlags())
    • 設置為模態(setModal(true))
    • 監聽父對象的destroyed信號,當父對象被銷毀時,將對話框的父對象設置為nullptr(使用setParent(nullptr))
    • 顯示對話框
  2. 靜態函數closeWait():關閉對話框
  3. 主窗口類(MainWindow):
    包含一個按鈕,點擊按鈕時執行槽函數on_pushButton_clicked()
  4. 在槽函數on_pushButton_clicked()中:
    • 創建QDialog*tempWidget = new QDialog();
    • tempWidget->setAttribute(Qt::WA_DeleteOnClose);
    • 調用CustomWaitDialog::waitShow(tempWidget);
    • 模擬耗時(使用QTimer單次觸發,在定時器結束后調用CustomWaitDialog::closeWait(),同時關閉tempWidget(因為設置了WA_DeleteOnClose,所以關閉即刪除))

class CustomWaitDialog : public QDialog {Q_OBJECT
public:static void waitShow(QWidget* parent) {CustomWaitDialog* dialog = getStaticDialog();if (parent != nullptr){// 綁定父子關系并設置模態dialog->setParent(parent, dialog->windowFlags() | Qt::Dialog);dialog->setModal(true);// 監聽父對象銷毀事件QObject::connect(parent, &QWidget::destroyed, dialog, [dialog]() {dialog->setParent(nullptr);  // 解除父子關系}, Qt::UniqueConnection);}if (dialog->isVisible()) {dialog->activateWindow();return;}dialog->show();}static void closeWait() {if (auto dialog = getStaticDialog()) {dialog->close();}}private:// 禁止外部創建實例explicit CustomWaitDialog(QWidget* parent = nullptr): QDialog(parent) {// 初始化對話框內容QLabel* label = new QLabel("Please wait...", this);QVBoxLayout* layout = new QVBoxLayout(this);layout->addWidget(label);}~CustomWaitDialog() {}static CustomWaitDialog* getStaticDialog() {static QPointer<CustomWaitDialog> instance = nullptr;if (instance.isNull()) {instance = new CustomWaitDialog();instance->setWindowTitle("Processing...");instance->resize(150, 150);}return instance;}};void MainWindow::on_pushButton_clicked()
{// 1. 創建臨時父窗口auto* tempContainer = new QDialog(this);tempContainer->setAttribute(Qt::WA_DeleteOnClose); // 關閉時自動刪除// 2. 顯示等待對話框tempContainer->setWindowTitle("等待中...");tempContainer->resize(this->size().width(), this->size().height());tempContainer->show();CustomWaitDialog::waitShow(tempContainer);// 3. 模擬耗時操作(實際中替換為真實操作)QTimer::singleShot(3000, this, [this, tempContainer]() {// 4. 關閉等待對話框CustomWaitDialog::closeWait();// 5. 關閉臨時容器(自動觸發WA_DeleteOnClose)tempContainer->close();// 6. 處理完成后續邏輯QMessageBox::information(this, "Complete", "Operation finished!");});
}

tempContainer父類析構時,setParent(nullptr)會輸出警告

External WM_DESTROY received for QWidgetWindow(0x201e71f52b0, name="CustomWaitDialogClassWindow") , parent: QWindow(0x0) , transient parent: QWindow(0x0)

  • 導致第二次再重復使用此靜態窗口時,不顯示;
    問題現象

也就是setParent(nullptr)后再使用窗口不顯示

解決方法一

  • 不監聽父對象銷毀事件和父類一起銷毀,每次使用都新new
 /*移除:監聽父對象銷毀事件QObject::connect(parent, &QWidget::destroyed, dialog, [dialog]() {dialog->setParent(nullptr);  // 解除父子關系}, Qt::UniqueConnection);*/

解決方法二

  • 更改父對象,避免窗口被外部(非Qt內部機制)強制銷毀 和每次使用都新new
// 方法二:更改父對象,避免窗口被外部(非Qt內部機制)強制銷毀 和每次new
QObject::connect(parent, &QWidget::destroyed, dialog, [dialog]() {auto pActive = qApp->activeWindow();if (pActive == nullptr) return; 	// 如果沒有活動窗口則和父類一起銷毀dialog->setParent(pActive);		// 轉移父窗口}, Qt::UniqueConnection);		

Windows系統強制銷毀窗口機制分析與Qt解決方案

Windows窗口銷毀機制

Windows系統強制銷毀子窗口的核心機制源于窗口所有權模型(Window Ownership Model)。當父窗口被銷毀時,系統會遞歸銷毀所有子窗口,這是通過發送WM_DESTROY消息實現的。關鍵點:

  1. 系統級行為

    • 父窗口銷毀時,Windows內核自動發送WM_DESTROY到所有子窗口
    • 這是Win32 API的底層行為(參考:微軟官方文檔)
    • Qt無法阻止此行為,只能通過父子關系管理規避
  2. Qt的封裝限制

    External WM_DESTROY received for QWidgetWindow(0x108b8cbdb10)
    

    該警告表明Qt的窗口對象(QWidgetWindow)已被系統強制銷毀,但Qt內部未同步此狀態,導致Qt窗口對象處于"僵尸狀態"。

問題根源分析

在代碼中:

QObject::connect(parent, &QWidget::destroyed, dialog, [dialog]() {dialog->setParent(nullptr);  // 在父對象銷毀后解除父子關系
});

此處存在時序問題

  1. 父窗口(tempContainer)開始銷毀
  2. Windows系統自動發送WM_DESTROY給子窗口(CustomWaitDialog)
  3. Qt收到系統消息,標記窗口為已銷毀狀態
  4. 隨后destroyed信號觸發,執行setParent(nullptr)
  5. 此時Qt窗口對象已被系統銷毀,但Qt嘗試修改其父子關系,導致狀態不一致

解決方案對比

方案一:每次創建新實例(簡單可靠)

? 優點:徹底避免僵尸窗口問題
? 缺點:頻繁創建/銷毀帶來輕微性能開銷

方案二:動態重設父窗口(需謹慎處理)

QObject::connect(parent, &QWidget::destroyed, dialog, [dialog]() {auto pActive = qApp->activeWindow();if (pActive == nullptr) return; 	// 如果沒有活動窗口則和父類一起銷毀dialog->setParent(pActive);		// 轉移父窗口}, Qt::UniqueConnection);
Windows強制銷毀的底層原理
  1. 窗口樹結構

    父窗口
    子窗口1
    子窗口2
    孫窗口

    父窗口銷毀時,整個子樹被遞歸銷毀

  2. 系統消息流

    DestroyWindow(hParent) 調用
    ├── 發送WM_DESTROY到hParent
    ├── 遞歸調用DestroyWindow(hChild1)
    ├── 遞歸調用DestroyWindow(hChild2)
    └── 最后釋放內存
    

    (參考:Windows消息序列)

  3. Qt的應對機制

    • QWidgetwinId()創建原生窗口句柄
    • 父子窗口關系通過SetParent()API建立
    • 系統級銷毀無法被Qt攔截,只能通過提前解除父子關系避免

    (參考:Windows消息序列)

  4. Qt的應對機制

    • QWidgetwinId()創建原生窗口句柄
    • 父子窗口關系通過SetParent()API建立
    • 系統級銷毀無法被Qt攔截,只能通過提前解除父子關系避免

關鍵結論:Windows的強制銷毀是系統級行為,Qt應用必須通過主動管理窗口生命周期來規避狀態不一致問題。對于不頻繁使用的等待對話框,推薦使用每次創建的模式,或結合QPointer的狀態驗證機制。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/87598.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/87598.shtml
英文地址,請注明出處:http://en.pswp.cn/web/87598.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

一文詳解Character AI:實用指南+ ChatGPT、Gemini對比分析

本指南將深入剖析Character AI的運行機制、功能特性及其存在的局限性。 近年來&#xff0c;生成式人工智能領域發展態勢迅猛&#xff0c;其應用范疇已遠超單純的文本生成領域。在眾多備受矚目的新興平臺中&#xff0c;Character AI是一款支持用戶以對話形式與人工智能生成角色…

遺傳算法的原理與實現示例

遺傳算法是一種受生物進化理論啟發的隨機優化算法&#xff0c;其核心思想是模擬自然界中 “物競天擇、適者生存” 的進化過程&#xff0c;通過對候選解的迭代優化&#xff0c;找到問題的最優解。 一、核心思想 遺傳算法將優化問題的候選解視為生物群體中的“個體”&#xff0c…

centos7 ping127.0.0.1不通

ping 127.0.0.1&#xff0c;localhost和本地ip都不通&#xff0c;所有的配置也是正確的 檢查下是否禁止了ping vim /proc/sys/net/ipv4/icmp_echo_ignore_all 內容為 1 禁止ping 內容為0 開啟ping sysctl -w net.ipv4.icmp_echo_ignore_all0 變更以上設置即可

【無標題】JavaScript入門

JS 1.JS引入方式 <!DOCTYPE html><html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>JS-引入方式</title><!-- …

(JAVA)自建應用調用企業微信API接口,實現消息推送

建議先簡單了解企業微信開發者中心文檔&#xff1a;開發前必讀 - 文檔 - 企業微信開發者中心 了解一下企業微信調用接口的基礎參數&#xff1a;基本概念介紹 - 文檔 - 企業微信開發者中心 本篇每個步驟都會跟著官網文檔走&#xff0c;都會貼上相關鏈接&#xff0c;看完本篇文…

P/Invoke 在默認封送(marshalling)規則下,常見托管 ? 非托管類型的對應關系

下表整理了 P/Invoke 在默認封送&#xff08;marshalling&#xff09;規則下&#xff0c;常見托管???非托管類型的對應關系。 內容主要依據微軟官方 Marshalling Data with?Platform?Invoke 文檔&#xff0c;并補充了常見指針&#xff0f;句柄用法與字符串緩沖區&#xff…

2.isaacsim4.2 教程-初識OmniGraph

1. OmniGraph&#xff08;視覺編程&#xff09; OmniGraph 是 Omniverse 的可視化編程框架。它提供了一個圖狀結構&#xff0c;將 Omniverse 內多個系統的功能節點串聯起來&#xff1b;同時也是一個計算框架&#xff0c;允許你編寫高度自定義的節點&#xff0c;將自己的功能無…

MonoGame 游戲開發框架日記 -03

第三章&#xff1a;創建類庫 內容介紹 主要內容&#xff1a;創建Core類并編寫 創建這個類主要是為了后續開發方便&#xff0c;并介紹游戲開發中的一種非常重要編程模式 單例模式&#xff0c;以及了解MonoGame基本圖形渲染知識單例模式&#xff1a; 第一步我們得先了解什么是單例…

AES 256 CBC加密和解密

AES-256-CBC 是一種對稱加密算法&#xff0c;使用 256位密鑰 和 CBC&#xff08;Cipher Block Chaining&#xff09;模式。它的典型使用場景包括對敏感信息進行加密存儲或傳輸。下面是 AES-256-CBC 的加密與解密的 Python 示例&#xff0c;使用 pycryptodome 庫&#xff1a; &a…

Git 版本控制完全指南:從入門到精通

Git 版本控制完全指南&#xff1a;從入門到精通 作為當今最流行的分布式版本控制系統&#xff0c;Git 已經成為開發者必備的技能之一。無論你是獨立開發者還是團隊協作&#xff0c;Git 都能幫助你高效管理代碼版本。本文將帶你從零開始&#xff0c;逐步掌握 Git 的核心概念和常…

408第三季part2 - 計算機網絡 - 計算機網絡分層結構

理解 PCI會放一些控制信息&#xff0c;源地址目的地址都在里面 SDU是放的數據 整個加起來是PDU 每一層的SDU都是上一層的PDU 看一看 也是簡單看一看就行 網絡層有時候也叫IP數據報 這里斷點下載的意思就是&#xff0c;你下載東西的時候網絡斷了&#xff0c;再連回來的時候會接…

打開攝像頭,服務器和客戶端傳輸攝像頭圖像數據

1&#xff1a;Camera Server 主要功能&#xff0c;打開攝像頭&#xff0c;接收客戶端請求 接收到客戶端請求“R”字符后開始傳輸攝像頭圖像。 #include "mainwindow.h" #include "ui_mainwindow.h"#include<QDebug>MainWindow::MainWindow(QWidget…

Android實現獲取前臺應用信息

Android實現獲取前臺應用信息 1.前言&#xff1a; 之前需要獲取在后臺運行的App信息&#xff0c;比如包名、版本這些常規的&#xff0c;今天是講解獲取在前臺的App信息&#xff0c;雖然App在前臺&#xff0c;但是具體的信息可能不知道&#xff0c;今天就嘗試獲取一下&#xf…

快訊|美團即時零售日訂單已突破1.2億,餐飲訂單占比過億

據美團內網公布信息顯示&#xff0c;截至22時54分&#xff0c;美團即時零售當日訂單已經突破了1.2億單&#xff0c;其中&#xff0c;餐飲訂單已超過1億單。 值得注意的是&#xff0c;就在當晚20時45分&#xff0c;美團內網曾顯示即時零售日訂單突破了1億。這也意味著&#xff…

pycharm2018配置gitee操作

一、gitee介紹及下載安裝 gitee介紹&#xff1a; gitee別名碼云&#xff0c;是中國的一個代碼托管平臺&#xff0c;類似于GitHub&#xff0c;基于Git技術&#xff0c;提供遠程倉庫托管、協作功能和開源社區服務&#xff0c;優勢包括訪問速度快、本地化服務和政策合規git和gite…

數據結構——棧的講解(超詳細)

數據結構——棧的講解&#xff08;超詳細&#xff09;-騰訊云開發者社區-騰訊云 #include"Stack.h" void STInit(ST* ps) {ps->arr NULL;ps->capacity ps->top 0; //總空間個數和有用空間個數都初始化為0 }void STDestroy(ST* ps) {if (ps -> arr) …

MySQL允許root用戶遠程連接

注意&#xff1a;在實際生產環境中&#xff0c;允許root用戶從任意主機&#xff08;‘%’&#xff09;連接存在安全風險&#xff0c;建議使用強密碼并限制訪問IP&#xff0c;或者創建具有必要權限的單獨用戶用于遠程連接。MySQL 配置遠程連接指南 1. 登錄 MySQL 服務器 mysql -…

STM32的 syscalls.c 和 sysmem.c

syscalls.c 是 STM32CubeIDE 自動生成的標準系統調用適配文件&#xff0c;用于裸機環境下支持 newlib 標準庫&#xff08;如 printf, scanf, malloc&#xff09;的運行。這份文件提供了標準庫運行所需的最小系統調用實現。現在我來逐段解析其作用&#xff0c;并補充你可能需要修…

Java零基礎筆記01(JKD及開發工具IDEA安裝配置)

1.Java簡介 Java是一種廣泛使用的計算機編程語言&#xff0c;由美國的Sun Microsystems公司&#xff08;Stanford University Network&#xff09;在1995年推出。Java以其跨平臺、面向對象、安全性高等特點&#xff0c;廣泛應用于企業級應用開發、移動應用開發等領域。2009年&a…

Spark SQL架構及高級用法

Spark SQL 架構概述 架構核心組件 API層&#xff08;用戶接口&#xff09; 輸入方式&#xff1a;SQL查詢&#xff1b;DataFrame/Dataset API。統一性&#xff1a; 所有接口最終轉換為邏輯計劃樹&#xff08;Logical Plan&#xff09;&#xff0c;進入優化流程。 編譯器層&…