判斷QMetaObject::invokeMethod()里的函數是否調用成功

? ? 今天,在Qt編程,碰到一個需要使用invokeMethod方式來獲取函數是否執行成功的情況。
? ? invokeMethod()即可以同步調用,也可以異步調用。若調用者、被調用者,都在同一個線程,則是同步調用;若調用者、被調用者,在不同線程,則是異步調用。
? ? 注意:只有同步調用,才能通過invokeMethod()的返回值,來判斷函數是否執行成功
? ? 比如,有如下精簡代碼:

//1)業務代碼
class ComWork : public QObject {Q_OBJECT
public:ComWork();signals:void sigSendResult(bool bOK);public slots:void SendCommand(QByteArray by) {qint64 nRet = m_pSerial->write(by);bool bOK = (nRet != -1);if(bOK)m_pSerial->flush();emit sigSendResult(bOK);} private:QSerialPort* m_pSerial;
};//2) 界面邏輯代碼
class ZoomWidget : public QWidget {
public:ZoomWidget (QWidget *parent= NULL);protected slots:void OnRecvCmdResult(bool bOK);private:QThread* m_pThread; //子線程ComWork* m_pWork;bool     m_bResult;
};ZoomWidget ::ZoomWidget (QWidget *parent): QWidget(parent)
{ui.setupUi(this);m_pThread = new QThread(this);m_pWork   = new ComWork();m_pWork->moveToThread(m_pThread); //m_pWork移動到子線程里,語句(a)//連接信號,語句(b)connect(m_pWork,&m_pWork::sigSendResult,this,ZoomWidget::OnRecvCmdResult);
}ZoomWidget::OnRecvCmdResult(bool bOK)
{m_bResult = bOK; //語句(c)qDebug()<<"recv status:"<<bOK;
}// 3)核心調用
ZoomWidget::DoSend()
{//進行調用,語句(d)QMetaObject::invokeMethod(m_pWork, "SendCommand", Qt::QueuedConnection, Q_ARG(QByteArray, sendData));
}

? ? 在Qt中,UI對象必須在主線程。而ZoomWidget是一個QWidtget,屬于UI對象,即ZoomWidget在主線程。
? ? 由語句(a)可知,m_pWork移動到了子線程里,即ZoomWidget與m_pWork不在同一個線程,
則在調用DoSend()函數時,QMetaObject::invokeMethod(m_pWork,…)其實是跨線程調用,也就是異步調用。而異步調用,由于"它不會等待函數是否執行,就直接返回了",即invokeMethod(,…Qt::QueuedConnection ,)函數,不會等待m_pWork的SendCommand()是否執行,就直接返回,并給出一個返回值,該返回值是無效的。
? ? 如果強制返回,Qt編譯也會報"QMetaMethod::invoke: Unable to invoke methods with return values in queued connections"錯誤。
? ? 但可以通過信號槽的方式,把異步調用的結果(比如語句(b)、語句?),返回給調用者(比如本例的ZoomWidget)。

? ? 這個 "Unable to invoke methods"的Qt 編譯報錯:

QMetaMethod::invoke: Unable to invoke methods with return values in queued connections

是一個非常常見的運行時錯誤,它的含義是:

你試圖使用 Qt::QueuedConnection(即異步方式)調用一個帶有返回值的方法,而這是 Qt 不支持的。


錯誤原因詳解

什么是 Qt::QueuedConnection

  • 它表示方法調用會在目標對象所在的線程中排隊執行(異步調用),而不是立即執行。
  • 常用于跨線程通信,比如從子線程調用主線程的 UI 方法。

為什么不能在 Qt::QueuedConnection 中使用帶返回值的函數?

  • 因為它是異步調用,調用者不會等待函數執行完成。
  • 所以無法通過 Q_RETURN_ARG(...) 拿到函數的返回值。
  • Qt 在底層會檢測這一點,并拋出警告或導致返回值無效。

示例代碼:錯誤寫法

int result = 0;
bool success = QMetaObject::invokeMethod(obj, "addNumbers",Qt::QueuedConnection, // ? 異步調用Q_RETURN_ARG(int, result),Q_ARG(int, 3),Q_ARG(int, 5));

上面這段代碼會導致報錯:

QMetaMethod::invoke: Unable to invoke methods with return values in queued connections

正確做法

? 方法一:使用 Qt::DirectConnection(同步調用)

如果你需要獲取返回值,請使用同步連接方式:

int result = 0;
bool success = QMetaObject::invokeMethod(obj, "addNumbers",Qt::DirectConnection, // ? 同步調用Q_RETURN_ARG(int, result),Q_ARG(int, 3),Q_ARG(int, 5));if (success) {qDebug() << "Result:" << result;
}

?? 注意:Qt::DirectConnection 要求調用線程和目標對象處于同一個線程,否則行為未定義。


? 方法二:避免返回值 + 使用信號傳遞結果(適合異步場景)

如果你確實需要跨線程調用并想獲取結果,可以這樣做:

步驟如下:
  1. 將原函數改為無返回值;
  2. 使用 QMetaObject::invokeMethod() 調用它;
  3. 函數內部處理完后,發出一個信號把結果傳回來。
示例代碼:
class Worker : public QObject {Q_OBJECTsignals:void resultReady(int result); // 用于返回結果public slots:void addNumbersAsync(int a, int b) {int result = a + b;emit resultReady(result); // 發送結果}
};
調用方式:
Worker* worker = new Worker();
worker->moveToThread(thread);// 連接信號與槽來接收結果
connect(worker, &Worker::resultReady, this, [](int res) {qDebug() << "異步返回結果:" << res;
});// 異步調用
QMetaObject::invokeMethod(worker, "addNumbersAsync",Qt::QueuedConnection,Q_ARG(int, 3),Q_ARG(int, 5));

總結1

場景是否允許返回值推薦連接方式備注
同一線程調用,需返回值? 是Qt::DirectConnection可使用 Q_RETURN_ARG
跨線程調用,需返回值? 否? 不可用必須用信號傳遞結果
跨線程調用,不需要返回值? 是Qt::QueuedConnection正常使用


QMetaObject::invokeMethod() 的返回值類型

bool QMetaObject::invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QGenericReturnArgument ret, ...)

返回值說明:

  • 返回類型:bool
  • 返回值含義:
    • true:表示方法成功調用。
    • false:表示方法調用失敗,可能原因包括:
      • 沒有找到名字匹配的方法(函數名錯誤或未聲明為 Q_INVOKABLEslot)。
      • 參數類型不匹配。
      • 對象已經被刪除(懸空指針)。
      • 使用了 Qt::QueuedConnection 但目標對象沒有運行事件循環。


如何進一步排查失敗原因?

雖然返回值只能告訴你是否成功,但你可以通過以下方式定位問題:

1. 檢查函數是否被正確聲明為 Q_INVOKABLEslot

class Worker : public QObject {Q_OBJECTpublic slots:void OpenPort(const QString &portName, int baudRate); // 必須匹配參數類型
};

或者:

Q_INVOKABLE void OpenPort(const QString &portName, int baudRate);

2. 確保對象沒有被釋放(避免懸空指針)

確保 m_pWork 是一個有效的 QObject* 指針,且對象尚未被 delete


3. 參數類型必須一致(支持元對象系統)

確保你使用的參數類型是 Qt 元對象系統支持的類型(如 int, QString, double 等),或者自定義類型已注冊:

Q_DECLARE_METATYPE(MyCustomType)
qRegisterMetaType<MyCustomType>();

4. 調試輸出所有可用方法(用于排查函數名/參數是否正確)

const QMetaObject* metaObj = m_pWork->metaObject();
for (int i = 0; i < metaObj->methodCount(); ++i) {qDebug() << metaObj->method(i).signature();
}

總結2

內容說明
invokeMethod() 是否有返回值?? 有,返回 bool 類型
true 表示什么?方法調用成功
false 表示什么?方法調用失敗(函數名錯誤、參數不匹配、對象無效、異步調用等)
可以用來做什么?判斷函數是否被成功調用,用于調試和錯誤處理

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

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

相關文章

【linux】特殊權限

us對文件&#xff1a;用戶執行該文件時&#xff0c;會以文件所有者的權限運行chmod us filename # 符號模式 chmod 4755 filename # 數字模式&#xff08;4表示SetUID&#xff09;典型應用&#xff1a;/usr/bin/passwd&#xff08;允許普通用戶修改自己的密碼&#xff0c;…

OpenCV:指紋識別

目錄 一、核心算法 1&#xff1a;SIFT 特征提取&#xff08;尺度不變特征變換&#xff09; 1.1 算法原理&#xff08;4 步核心流程&#xff09; 1.2 重點代碼實現與參數解析 1.3 關鍵輸出解讀 二、核心算法 2&#xff1a;FLANN 特征匹配&#xff08;快速最近鄰搜索&#x…

快速排序:高效的分治排序算法

快速排序因其平均時間復雜度$O(n\log n)$而成為廣泛應用的高效排序算法。其核心是分治法: 選擇基準 (Pivot):從待排序序列中選取一個元素(如第一個元素$arr[0]$)。 分區 (Partition):將序列重新排列,所有小于基準的元素置于其前,大于或等于的置于其后。基準元素最終位于…

網絡編程之UDP廣播與粘包問題

一&#xff0c;廣播簡介從上述講的例?中&#xff0c;不管是TCP協議還是UDP協議&#xff0c;都是”單播”, 就是”點對點”的進?通信&#xff0c;如果要對網絡里面的所有主機進?通信&#xff0c;實現”點對多”的通信&#xff0c;我們可以使用UDP中的?播通信。 理論上可以像…

教育領域大模型生成題目安全研究報告

教育領域大模型生成題目安全研究報告 一、研究背景與意義 隨著大語言模型&#xff08;LLM&#xff09;在教育領域的深度應用&#xff0c;自動生成題目已成為提升教學效率、實現個性化教學的關鍵技術手段&#xff0c;廣泛應用于課堂練習、作業布置、考試命題等場景。然而&…

Android安卓項目調試之Gradle 與 Gradle Wrapper的概念以及常用gradle命令深度詳解-優雅草卓伊凡

Android安卓項目調試之Gradle 與 Gradle Wrapper的概念以及常用gradle命令深度詳解-優雅草卓伊凡好的&#xff0c;我們來詳細梳理一下 Android 開發中 Gradle 的常用配置和調試命令。這對于每一位 Android 開發者來說都是必須掌握的核心技能。第一部分&#xff1a;Gradle 與 Gr…

Maven入門_簡介、安裝與配置

ZZHow(ZZhow1024) 參考課程&#xff1a; 【尚硅谷新版Maven教程】 [https://www.bilibili.com/video/BV1JN411G7gX] 一、Maven簡介 02_依賴管理工具 解決 jar 包的規模問題解決 jar 包的來源問題解決 jar 包的導入問題解決 jar 包之間的依賴 03_構建工具 我們沒有注意過…

Spark(1):不依賴Hadoop搭建Spark環境

不依賴Hadoop搭建Spark環境0 概述1 單機安裝Spark1.1 下載Spark預編譯包1.2 解壓和設置1.3 配置環境變量1.4 驗證安裝2 Spark運行模式2.1 Local模式&#xff08;本地模式&#xff09;2.1.1 Spark Shell2.1.1.1 Python版的Shell2.1.1.2 Scala版的Shell2.1.2 提交獨立的Spark應用…

【ThreeJs】【自帶依賴】Three.js 自帶依賴指南

&#x1f6e0;? Three.js 輔助庫生態手冊 定位&#xff1a;覆蓋 90% 開發場景的工具選型實操指南&#xff0c;區分「入門必備」和「進階擴展」。 適用人群&#xff1a;Three.js 新手&#xff08;≥ r132 版本&#xff09;、需要規范開發流程的團隊。 1. 控制器&#xff08;Co…

Mac電腦上如何打印出字體圖標

背景 我今天打開了一個之前開發的APP&#xff0c;看到項目中用到了字體圖標&#xff0c;發現有個“面條”圖標用錯了&#xff0c;想著修改一下吧。然后用輸入法打出”面條“&#xff0c;在輸入法的彈窗中就一直往下找&#xff0c;發現并沒有出現圖標。 想著打出”面條圖標“也沒…

當AI遇上數據庫:Text2Sql.Net如何讓“說人話查數據“成為現實

一句話概括&#xff1a;還在為寫復雜SQL而頭疼&#xff1f;Text2Sql.Net讓你用自然語言就能查數據庫&#xff0c;堪稱程序員的"數據庫翻譯官"&#xff01; &#x1f3af; 引言&#xff1a;從"SQL地獄"到"自然語言天堂" 想象一下這樣的場景&…

整體設計 之 緒 思維導圖引擎 之 引 認知系統 之8 之 序 認知元架構 之4 統籌:范疇/分類/目錄/條目 之2 (豆包助手 之6)

問題Q68、我們現在僅僅分析了 認知演進 的 “進”的問題&#xff0c;通過層次結構 和 統籌 的同構約束 給出了 不同對象及其對應的操作和約束。 --這句話 你能完全理解嗎&#xff08;這意味著 完整的程序細節設計&#xff09;。 還沒有分析的還有 “演” 以及組合詞 “演進” -…

開始 ComfyUI 的 AI 繪圖之旅-Qwen-Image-Edit(十二)

文章標題一、Qwen-Image-Edit1.ComfyOrg Qwen-Image-Edit 直播回放2.Qwen-Image-Edit ComfyUI 原生工作流示例2.1 工作流文件2.2 模型下載3.3 按步驟完成工作流一、Qwen-Image-Edit Qwen-Image-Edit 是 Qwen-Image 的圖像編輯版本&#xff0c;基于20B模型進一步訓練&#xff0c…

機械制造專屬ERP:降本增效與數字轉型的關鍵

轉型升級壓力下&#xff0c;ERP系統是機械企業破局的得力助手。本文深入解析ERP的核心功能、選型要點與實施價值&#xff0c;助您精準選型&#xff0c;賦能智能制造&#xff0c;全面提升競爭力。在數字化浪潮席卷之下&#xff0c;機械制造企業正面臨提質、增效、降本的關鍵轉型…

npm / yarn / pnpm 包管理器對比與最佳實踐(含國內鏡像源配置與緩存優化)

這篇不是“誰更快”的玄學討論,而是把團隊能落地的做法一次說清:如何選型、如何統一版本、如何把鏡像與緩存配好、如何在 CI 和 Monorepo 下穩住“可重復構建”。 一、結論先說在前 單倉庫 / 以穩定為先:直接用 npm(配合 npm ci) 足夠,維護成本低,生態一等一,Node 16.1…

Python項目全面打包指南:從EXE到綠色軟件包

?? Python項目全面打包指南:從EXE到綠色軟件包 文章目錄 ?? Python項目全面打包指南:從EXE到綠色軟件包 1 打包基礎概念與工具選型 1.1 核心打包概念 1.2 工具對比與選型 2 項目環境準備與依賴管理 2.1 創建和管理虛擬環境 2.2 依賴管理最佳實踐 2.3 依賴導出與規范文件處…

JAVA:Spring Boot 集成 FFmpeg 實現多媒體處理

1、簡述 在現代 Web 應用中,音視頻處理需求越來越常見,例如:視頻轉碼、截圖、音頻提取、格式轉換等。FFmpeg 是一個功能極其強大的開源音視頻處理工具,可以幫助我們高效完成這些任務。本文將介紹如何在 Spring Boot 項目中集成 FFmpeg,并實現一些常見的應用場景。 2、為什…

推薦一款智能三防手機:IP68+天璣6300+PoC對講+夜視

在戶外探險、工業巡檢及應急通信等專業領域&#xff0c;傳統智能手機往往難以應對復雜苛刻的環境挑戰。智能三防手機憑借其堅固的機身、專業的防護能力及定制化功能&#xff0c;成為眾多行業用戶的可靠工具。本文將深入解析一款集IP68防護、天璣6300處理器、PoC公網對講及夜視等…

ego(4)---檢測B樣條軌跡的障礙物進入點與退出點

障礙物進出點檢測的作用在經過 B 樣條的控制點采樣后&#xff0c;接下來是繞障的環節&#xff0c;繞障使用的是 Astar &#xff0c;但在使用 Astar 之前&#xff0c;需要進行障礙物進出點的檢測與標記。通俗點講&#xff0c;這部分的作用就是為 Astar 繞障礙做前置準備。檢測進…

在springboot中使用mock做controller層單元測試,請求示例包括GET(帶參數)、POST(帶請求頭)、下載文件、上傳文件等

以下是SpringBoot中使用MockMvc進行Controller層單元測試的完整示例,涵蓋GET帶參數、POST帶請求頭、文件下載和文件上傳等場景: GET請求測試(帶路徑參數) @Test void testGetWithPathParam() throws Exception {mockMvc.perform(MockMvcRequestBuilders.