初探Qt信號與槽機制

3.3 按鍵響應 - 初識信號與槽
3.3.1 信號與槽基本介紹
提出疑問,界面上已經有按鍵了,怎么操作才能讓用戶按下按鍵后有操作上的反應呢?
Qt 中, 信號和槽機制 是一種非常強大的事件通信機制。這是一個重要的概念,特別是對于初學者來 說,理解它對于編寫 Qt 程序至關重要。
概要
1. 信號 (Signals) :是由對象在特定事件發生時發出的消息。例如, QPushButton 有一個
clicked() 信號,當用戶點擊按鈕時發出。
2. (Slots) :是用來響應信號的方法。一個槽可以是任何函數,當其關聯的信號被發出時,該槽函數 將被調用。
3. 連接信號和槽 :使用 QObject::connect() 方法將信號連接到槽。當信號發出時,關聯的槽函數
會自動執行。
3.3.2 按鍵 QPushButton 設置信號與槽
Qt 中,有幾種不同的方式來設置按鍵信號與槽的連接,主要包括:
Qt的信號和槽機制是其事件處理系統的核心。這種機制允許對象之間的通信,而不需要它們知道對方的 具體實現。以下是Qt信號和槽的幾種常見連接方式的簡要概述,我將它們整理成表格形式以便于理解:
這些方式各有優劣,選擇哪種方式取決于具體的應用場景、代碼風格以及個人偏好。例如,直接使用 QObject::connect 是最通用的方式,而使用 Lambda 表達式可以在同一位置編寫信號處理邏輯,提高 代碼的可讀性。使用函數指針的方式則在編譯時提供更好的類型檢查。自動連接通常在使用Qt Designer 設計UI 時比較方便。
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//在構造函數中進行信號與槽的綁定
//第二種方式:QObject::connect(sender, SIGNAL(signal()), receiver,
SLOT(slot()));
QObject::connect(ui->btnCon, SIGNAL(clicked()), this,
SLOT(on_btnCon_clickedMyself()));
//第三方式:lambda表達式:QObject::connect(sender, &Sender::signal, [=]() { /*
lambda body */ });
QObject::connect(ui->btnLambda, &QPushButton::clicked,[=](){
std::cout << "btnLambdaClicked" << std::endl;
});
//第四種方式:QObject::connect(sender, &Sender::signal, receiver,
&Receiver::slot);
QObject::connect(ui-
>btnFortch,&QPushButton::clicked,this,&Widget::on_fortch_clicked);
}
Widget::~Widget()
{
delete ui;
}
//第一種方式:通過uiDesigner
void Widget::on_btnui_clicked()
{
std::cout << "UIBtnClicked" << std::endl;
}
void Widget::on_btnCon_clickedMyself()
{
std::cout << "btnConClicked" << std::endl;
}
void Widget::on_fortch_clicked()
{
std::cout << "btnForthClicked" << std::endl;
}
3.3.3 自定義信號與槽
Qt 中,自定義信號與槽是實現對象間通信的一種機制。信號和槽是 Qt 對象通信的核心特性,使得一個
對象能夠在發生某種事件時通知其他對象。自定義信號與槽的實現步驟如下:
1. 定義信號 :在 Qt 中,信號是由 signals 關鍵字聲明的類成員函數。它們不需要實現,只需聲明。例
如:
class MyClass : public QObject {
Q_OBJECT
public:
MyClass();
signals:
void mySignal(int value);
};
在上面的例子中, MyClass 有一個名為 mySignal 的信號,它帶有一個整型參數。
定義槽 :槽可以是任何普通的成員函數,但通常在類定義中用 slots 關鍵字標識。槽可以有返回類型,
也可以接受參數,但它們的參數類型需要與發出信號的參數類型匹配。例如:
class MyClass : public QObject {
Q_OBJECT
public slots:
void mySlot(int value);
};
在這個例子中,我們定義了一個名為 mySlot 的槽,它接收一個整型參數。
連接信號與槽 :使用 QObject::connect 函數將信號與槽連接起來。當信號被發射時,連接到這個信號的槽將被調用。
MyClass *myObject = new MyClass();
connect(myObject, SIGNAL(mySignal(int)), myObject, SLOT(mySlot(int)));
這行代碼連接了 myObject mySignal 信號到同一個對象的 mySlot 槽。
發射信號 :使用 emit 關鍵字發射信號。當信號被發射時,所有連接到這個信號的槽都會被調用。
emit mySignal(123);
這將觸發所有連接到 mySignal 的槽。
自定義信號和槽是 Qt 編程中非常強大的特性,它們使得組件之間的通信變得靈活而松耦合。通過信和 槽,可以方便地實現各種復雜的事件驅動邏// 輯。

//widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <iostream>
#include <QDebug>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
signals:
void mysignal();
void mysignalparams(int value);
private slots:
void myslot();
void myslotparams(int value);
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
//widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
connect(this,SIGNAL(mysignal()),this,SLOT(myslot()));
connect(this,SIGNAL(mysignalparams(int)),this,SLOT(myslotparams(int)));
emit mysignal();
emit mysignalparams(100);
}
Widget::~Widget()
{
delete ui;
}
void Widget::myslot()
{
std::cout << "myslot" << std::endl;
}
void Widget::myslotparams(int value)
{
qDebug() << "myslotparams";
qDebug() << value ;
}

QDebug()
QDebug Qt 框架中用于輸出調試信息的一個類。它提供了一種方便的方式來輸出文本到標準輸出(通 常是控制臺),這對于調試 Qt 應用程序非常有用。 QDebug 類可以與 Qt 的信號和槽機制一起使用,使 得在響應各種事件時能夠輸出有用的調試信息。
使用 QDebug 的一個典型方式是通過 qDebug() 函數,它返回一個 QDebug 對象。然后,可以使用流操 作符 << 來輸出各種數據類型。例如:
qDebug() << "This is a debug message";
int value = 10;
qDebug() << "The value is" << value;
當執行這些代碼時,它們會在應用程序的控制臺輸出相應的文本。這對于檢查程序的運行狀態、變量的 值或者跟蹤程序的執行流程非常有幫助。
還可以使用 qDebug() 來輸出自定義類型,只要為這些類型提供了適當的輸出操作符重載。此外, Qt 還 提供了 qInfo() , qWarning() , qCritical() qFatal() 函數,用于輸出不同級別的信息,分別用
于普通信息、警告、關鍵錯誤和致命錯誤。這有助于對日志信息進行級別劃分,從而更好地控制輸出內容。
QMetaObject::connectSlotsByName: No matching signal for on_pushButton_clicked()
QMetaObject::connectSlotsByName: No matching signal for on_btnCon_clickedMyself()
QObject::connect: Parentheses expected, signal QPushButton::clicked in ..\signalAndSlot\widget.cpp:11
QObject::connect:  (sender name:   'btnCon')
QObject::connect:  (receiver name: 'Widget')
Can't find filter element
Can't find filter element
16:25:47: E:\QT\build-signalAndSlot-Desktop_Qt_5_12_12_MinGW_32_bit-Debug\debug\signalAndSlot.exe exited with code 0

你提供的這段日志信息是 Qt 程序運行時的調試輸出,主要涉及 信號與槽機制 的錯誤提示。下面我將逐條解釋這些錯誤信息的含義,并給出可能的原因和解決方法。


🧾 錯誤日志分析

1.?QMetaObject::connectSlotsByName: No matching signal for on_pushButton_clicked()

  • 含義

    • Qt 嘗試自動連接名為?on_pushButton_clicked()?的槽函數(即按鈕點擊事件)。
    • 但沒有找到對應的信號(比如?QPushButton::clicked())來綁定這個槽函數。
  • 常見原因

    • 沒有在?.ui?文件中正確命名控件為?pushButton
    • 或者你在代碼中動態創建了按鈕,但沒有手動連接信號和槽。
    • 或者你寫了?on_pushButton_clicked()?函數,但并沒有通過?connect()?或 UI 自動連接機制進行綁定。
  • 解決辦法

    • 如果你使用的是 Qt Designer 設計界面,請確保按鈕的?objectName?是?pushButton
    • 如果你是手動創建按鈕,請使用如下方式手動連接:
      connect(ui->pushButton, &QPushButton::clicked, this, &Widget::on_pushButton_clicked);

2.?QMetaObject::connectSlotsByName: No matching signal for on_btnCon_clickedMyself()

  • 含義

    • 同樣是找不到與槽函數?on_btnCon_clickedMyself()?對應的信號。
  • 常見原因

    • 你定義了一個自定義的槽函數名?on_btnCon_clickedMyself(),但 Qt 默認只識別標準命名格式如?on_<控件名>_<信號名>()
    • 例如:on_btnCon_clicked()?是合法的;而?on_btnCon_clickedMyself()?不符合默認規則,不會被自動連接。
  • 解決辦法

    • 建議使用標準命名方式,如:
      void on_btnCon_clicked();
    • 或者如果你堅持要使用自定義名稱,必須手動連接信號和槽
      connect(ui->btnCon, &QPushButton::clicked, this, &Widget::on_btnCon_clickedMyself);

3.?QObject::connect: Parentheses expected, signal QPushButton::clicked in ..\signalAndSlot\widget.cpp:11

  • 含義

    • 在第 11 行調用?connect()?時,參數中的信號寫法不正確。
    • 可能你漏掉了括號或者寫成了?QPushButton::clicked?而不是?&QPushButton::clicked
  • 錯誤示例

    connect(ui->btnCon, QPushButton::clicked, this, Widget::on_btnCon_clicked); // ? 錯誤
  • 正確寫法

    connect(ui->btnCon, &QPushButton::clicked, this, &Widget::on_btnCon_clicked); // ? 正確

4.?QObject::connect: (sender name: 'btnCon')

5.?QObject::connect: (receiver name: 'Widget')

  • 含義
    • 這只是調試信息,顯示發送者是名字為?btnCon?的對象(按鈕),接收者是?Widget?類的對象(主窗口)。

6.?Can't find filter element?×2

  • 含義

    • 這個警告通常出現在你嘗試使用?事件過濾器(eventFilter),但傳入了一個未注冊或無效的?QObject
    • 或者你在某些地方調用了類似:
      ui->someWidget->installEventFilter(this);
      但是沒有實現?eventFilter()?函數,或者傳入了錯誤的對象。
  • 解決辦法

    • 檢查是否使用了?installEventFilter()
    • 如果使用了,請確保實現了?bool eventFilter(QObject *obj, QEvent *event)?函數。
    • 或者移除未使用的事件過濾代碼。

7.?exited with code 0

  • 含義
    • 程序正常退出,沒有崩潰,也沒有異常終止。
    • 所以雖然有警告,但程序本身沒有致命錯誤。

? 總結:你需要檢查以下幾點

問題檢查點建議
No matching signal for ...是否控件名一致?是否手動連接?使用標準命名或手動連接
Parentheses expected是否漏掉了?&?或寫錯了信號名?檢查?connect()?寫法
Can't find filter element是否誤用了?eventFilter檢查?installEventFilter()?和?eventFilter()?實現

? 示例修復代碼片段

// widget.h
private slots:void on_pushButton_clicked();               // 標準命名,可自動連接void on_btnCon_clickedMyself();             // 自定義命名,需手動連接// widget.cpp
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 手動連接自定義命名的槽函數connect(ui->btnCon, &QPushButton::clicked, this, &Widget::on_btnCon_clickedMyself);
}void Widget::on_pushButton_clicked()
{qDebug() << "Standard button clicked";
}void Widget::on_btnCon_clickedMyself()
{qDebug() << "Custom slot function called";
}

如果你愿意貼出你的完整 .h.cpp 文件,我可以幫你具體定位錯誤位置并修改。

需要我繼續協助嗎?

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include<iostream>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_pushButton_clicked();void on_btnCon_clickedMyself();private:Ui::Widget *ui;
};
#endif // WIDGET_H

當然可以!下面是對這段 Qt Widgets 應用程序的頭文件 widget.h逐行詳細注釋解釋,幫助你理解這個類的結構、功能和 Qt 相關機制。


🔁 頭文件衛士(防止重復包含)

 

cpp

深色版本

#ifndef WIDGET_H
#define WIDGET_H

說明:這是“頭文件衛士”(Include Guard),用于防止該頭文件被多次包含導致重復定義。

  • 如果?WIDGET_H?沒有被定義過,就繼續編譯以下內容;
  • 否則跳過整個頭文件內容。

📦 引入標準庫頭文件

 

cpp

深色版本

#include <QWidget>

說明:引入 Qt 提供的 QWidget 類,它是所有 GUI 控件的基礎類。當前 Widget 類將繼承自它。

 

cpp

深色版本

#include <iostream>

說明:引入 C++ 標準輸入輸出流庫,可能用于調試輸出(如 std::cout)。


🧱 聲明 UI 命名空間(由 .ui 文件生成)

 

cpp

深色版本

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

說明

  • QT_BEGIN_NAMESPACE?和?QT_END_NAMESPACE?是 Qt 的命名空間宏,用于將 Qt 的類放在?Qt?命名空間中(在某些配置下啟用)。
  • namespace Ui { class Widget; }?是對?Ui::Widget?類的前置聲明。
    • 這個類是由?.ui?設計文件自動生成的,里面包含了界面控件(如按鈕、標簽等)。
    • 在?.cpp?文件中會通過?ui->控件名?來訪問這些控件。

🏗? 定義?Widget?類

 

cpp

深色版本

class Widget : public QWidget
{Q_OBJECT

說明

  • 定義一個類?Widget,它繼承自?QWidget,是一個自定義的窗口部件。
  • Q_OBJECT?是一個宏,必須出現在類定義中,如果你希望這個類支持:
    • 信號與槽機制(signals/slots)
    • 動態屬性(dynamic properties)
    • 國際化支持(tr() 函數)
    • 元對象系統(Meta-Object)

🧩 構造函數與析構函數

 

cpp

深色版本

public:Widget(QWidget *parent = nullptr);~Widget();

說明

  • Widget(QWidget *parent = nullptr);:構造函數,默認參數為?nullptr,表示沒有父窗口。
  • ~Widget();:析構函數,用于釋放資源(如界面指針?ui)。

💡 私有槽函數(Private Slots)

 

cpp

深色版本

private slots:void on_pushButton_clicked();void on_btnCon_clickedMyself();

說明

  • private slots:?表示這些函數是 Qt 的槽函數(Slot),可以響應信號(Signal),比如按鈕點擊事件。
  • 這兩個函數的作用分別是:
    • on_pushButton_clicked():當名為?pushButton?的按鈕被點擊時自動調用(基于 Qt 的自動連接命名規則)。
    • on_btnCon_clickedMyself():這是一個自定義命名的槽函數,不會被 Qt 自動識別綁定,需要手動連接信號與槽

💾 私有成員變量

 

cpp

深色版本

private:Ui::Widget *ui;

說明

  • 這是一個指向?Ui::Widget?的指針,用于訪問你在 Qt Designer 中設計的圖形界面。
  • 實際上,.ui?文件會被 Qt 自動轉換成?ui_widget.h?文件,在?.cpp?文件中通過?ui->控件名?訪問界面上的按鈕、標簽等。

? 結束頭文件衛士

 

cpp

深色版本

};
#endif // WIDGET_H

說明:結束 #ifndef WIDGET_H 的條件編譯塊,確保這個頭文件不會被多次包含。


📌 總結結構圖

組件內容
頭文件衛士防止重復包含
引用頭文件#include <QWidget>?和?#include <iostream>
UI 前置聲明namespace Ui { class Widget; }
類定義class Widget : public QWidget
支持 Qt 特性Q_OBJECT?宏
構造/析構函數初始化窗口、釋放資源
槽函數on_pushButton_clicked()?和?on_btnCon_clickedMyself()
UI 成員指針Ui::Widget *ui;,用于操作界面控件

🧠 小貼士

  • 如果你使用了 Qt Designer 設計界面,請確保按鈕的?objectName?是?pushButton?或?btnCon,這樣 Qt 才能正確找到并綁定槽函數。
  • 對于?on_btnCon_clickedMyself()?這樣的自定義命名槽函數,你需要在?.cpp?文件中手動連接信號與槽:
     cpp 

    深色版本

    connect(ui->btnCon, &QPushButton::clicked, this, &Widget::on_btnCon_clickedMyself);

如果你還需要我幫你分析 .cpp 文件或修復信號槽相關錯誤,歡迎繼續提問 😊

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//在構造函數中進行槽和信號的綁定//QObject::connect(sender,SIGNAL(signal()),receiver, SLOT(slot()));QObject::connect(ui->btnCon, SIGNAL(clicked), this, SLOT(on_btnCon_clickedMyself()));
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_clicked()
{std::cout << "UIBTNClicked" << std::endl;
}void Widget::on_btnCon_clickedMyself()
{std::cout << "btnConClicked" << std::endl;
}

這段代碼是一個 Qt Widgets 應用程序的實現文件(widget.cpp,用于定義主窗口類 Widget 的構造函數、析構函數和兩個槽函數。它實現了基本的 信號與槽機制 來響應按鈕點擊事件。

下面是對整段代碼的逐行詳細注釋解釋,幫助你理解每一行的作用以及 Qt 中的信號與槽機制。


📁 引入頭文件

#include "widget.h"

包含當前類的頭文件,聲明了 Widget 類的基本結構、成員函數和成員變量。

#include "ui_widget.h"

引入由 Qt Designer 生成的 UI 頭文件。

  • 這個文件是根據?.ui?文件自動生成的,里面定義了界面上的所有控件(如按鈕、標簽等)。
  • Ui::Widget?是一個命名空間中的類,包含了這些控件的指針。

🔧 構造函數實現

Widget::Widget(QWidget *parent): QWidget(parent)          // 調用父類 QWidget 的構造函數, ui(new Ui::Widget)       // 動態創建一個 Ui::Widget 對象
{ui->setupUi(this);         // 初始化界面布局,把 .ui 設計的界面加載到當前窗口
  • 創建?Widget?窗口對象;
  • 使用?ui->setupUi(this)?把你在 Qt Designer 中設計的?.ui?界面加載進來。
    // 在構造函數中進行槽和信號的綁定// QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));QObject::connect(ui->btnCon, SIGNAL(clicked), this, SLOT(on_btnCon_clickedMyself()));
}

說明

  • 使用 Qt 的經典宏方式連接信號與槽。
  • 當?btnCon?按鈕被點擊時,會觸發?clicked()?信號,并調用?on_btnCon_clickedMyself()?槽函數。
  • 注意:這種寫法使用的是?Qt4 的 SIGNAL/SLOT 宏語法,不推薦在新項目中使用(沒有編譯期檢查),建議改用?Qt5 的 Lambda 或函數指針方式

🧼 析構函數實現

Widget::~Widget()
{delete ui; // 手動釋放 ui 指針指向的對象所占用的內存,防止內存泄漏
}

析構函數在對象銷毀時自動調用,用于清理資源。


💡 槽函數實現

1.?on_pushButton_clicked()

void Widget::on_pushButton_clicked()
{std::cout << "UIBTNClicked" << std::endl;
}
  • 這是一個標準命名的槽函數:on_<控件名>_<信號名>()
  • 如果你在?.ui?文件中有一個名為?pushButton?的按鈕,Qt 會自動將它的?clicked()?信號連接到這個函數。
  • 作用:當按鈕被點擊時輸出?"UIBTNClicked"?到控制臺。

2.?on_btnCon_clickedMyself()

void Widget::on_btnCon_clickedMyself()
{std::cout << "btnConClicked" << std::endl;
}
  • 這是一個自定義命名的槽函數
  • 因為名字不是標準格式?on_<控件名>_clicked(),所以不會自動連接,必須手動調用?connect()
  • 在構造函數中已經通過?QObject::connect(...)?將?btnCon?的?clicked()?信號綁定到了這個函數。
  • 作用:當按鈕?btnCon?被點擊時輸出?"btnConClicked"?到控制臺。

? 總結輸出結果(當你點擊按鈕時)

按鈕輸出內容
pushButton?被點擊UIBTNClicked
btnCon?被點擊btnConClicked

?? 建議改進:使用 Qt5 推薦的連接方式

目前你使用的是 Qt4 的 SIGNAL()SLOT() 宏方式,這種方式在運行時才會報錯,不利于調試。

? 推薦改寫成 Qt5 的方式

connect(ui->btnCon, &QPushButton::clicked, this, &Widget::on_btnCon_clickedMyself);

或者使用 Lambda 表達式:

connect(ui->btnCon, &QPushButton::clicked, this, [=]() {std::cout << "btnConClicked (Lambda)" << std::endl;
});

📌 最佳實踐總結

內容建議
信號與槽連接方式使用 Qt5 的函數指針或 Lambda 表達式
槽函數命名標準命名可自動綁定,否則需手動連接
控件命名一致性.ui?文件中控件的?objectName?必須與代碼一致
內存管理手動刪除?ui?指針,避免內存泄漏

如果你還想了解:

  • 如何使用 Qt Designer 添加按鈕并自動綁定槽函數
  • 如何添加更多控件并在代碼中操作它們
  • 如何使用布局管理器(Layout)來美化界面

歡迎繼續提問,我可以幫你一步步完善你的 Qt 程序 😊

E:\QT\build-signalAndSlot-Desktop_Qt_5_12_12_MinGW_32_bit-Debug\debug\moc_widget.cpp:80: error: undefined reference to `Widget::on_pushButton_clicked()'
debug/moc_widget.o: In function `ZN6Widget18qt_static_metacallEP7QObjectN11QMetaObject4CallEiPPv':
E:\QT\build-signalAndSlot-Desktop_Qt_5_12_12_MinGW_32_bit-Debug/debug/moc_widget.cpp:80: undefined reference to `Widget::on_pushButton_clicked()'

你遇到的這個錯誤:

 

深色版本

undefined reference to `Widget::on_pushButton_clicked()'

鏈接階段(Linking)報錯,說明編譯器在生成最終可執行文件時找不到函數 void Widget::on_pushButton_clicked() 的定義。


🚨 錯誤原因分析

? 你在頭文件中聲明了該函數:

 

cpp

深色版本

private slots:void on_pushButton_clicked();

? 但你在?.cpp?文件中沒有定義它?或者?定義拼寫不一致

你貼出的 .cpp 文件中:

 

cpp

深色版本

void Widget::on_pushButton_clicked()
{std::cout << "UIBTNClicked" << std::endl;
}

看起來你是寫了這個函數的。那為什么還會報錯呢?


🔍 可能原因總結

? 原因 1:未重新構建項目(qmake 沒有重新生成 moc 文件)

Qt 使用元對象編譯器(moc)來處理信號與槽機制。如果你:

  • 添加了新的槽函數;
  • 修改了類的結構并忘記重新運行 qmake;

就可能導致 moc_widget.cpp 中仍然引用了一個不存在或未正確編譯的函數。

🔧 解決方法:

  1. 清理項目(Build → Clean All)
  2. 重新運行 qmake(Build → Run qmake)
  3. 重新構建項目(Build → Build All)

? 原因 2:槽函數拼寫錯誤或簽名不一致

確保你的函數簽名完全匹配,包括:

  • 返回類型(必須是?void
  • 函數名(必須是?on_pushButton_clicked()
  • 參數列表(必須為空)

? 正確:

 

cpp

深色版本

void Widget::on_pushButton_clicked()
{// ...
}

? 錯誤示例:

 

cpp

深色版本

void on_pushButton_clicked() // 沒有作用域 Widget::
void Widget::on_pushButton_clicked(int) // 多了參數

? 原因 3:.pro?文件中缺少?QT += widgets

如果你的 .pro 文件中沒有包含 Widgets 模塊:

 

qmake

深色版本

QT += core gui

而沒有:

 

qmake

深色版本

QT += widgets

會導致一些 Qt Widgets 類(如 QPushButton)無法正確鏈接。

🔧 解決方法: 修改 .pro 文件為:

 

qmake

深色版本

QT += core gui widgets

然后清理、運行 qmake、重新構建。


? 原因 4:IDE 緩存問題 / 構建路徑混亂

有時 IDE(比如 Qt Creator)緩存了舊版本的 moc 文件或中間文件。

🔧 解決方法:

  • 刪除項目的?build?目錄(或 Debug/Release 子目錄)
  • 重新打開項目并重新構建

? 最終檢查清單

檢查項是否完成
函數是否正確定義??
函數簽名是否完全一致??
是否清理并重新構建項目??
.pro?文件中是否包含?QT += widgets?
是否刪除 build 并重新構建??

? 示例修復后的完整?.cpp?文件

 

cpp

深色版本

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);connect(ui->btnCon, &QPushButton::clicked, this, &Widget::on_btnCon_clickedMyself);
}Widget::~Widget()
{delete ui;
}// 必須正確定義這個槽函數
void Widget::on_pushButton_clicked()
{std::cout << "UIBTNClicked" << std::endl;
}void Widget::on_btnCon_clickedMyself()
{std::cout << "btnConClicked" << std::endl;
}

? 推薦使用 Qt5 的連接方式(更安全)

 

cpp

深色版本

connect(ui->pushButton, &QPushButton::clicked, this, &Widget::on_pushButton_clicked);

而不是使用宏方式(容易出錯):

 

cpp

深色版本

connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(on_pushButton_clicked()));

如果你已經確認以上所有內容,但問題依舊,請貼出你的 .pro 文件和完整的項目結構,我可以進一步幫你診斷。

/****************************************************************************
** Meta object code from reading C++ file 'widget.h'
**
** Created by: The Qt Meta Object Compiler version 67 (Qt 5.12.12)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/#include "../../signalAndSlot/widget.h"
#include <QtCore/qbytearray.h>
#include <QtCore/qmetatype.h>
#if !defined(Q_MOC_OUTPUT_REVISION)
#error "The header file 'widget.h' doesn't include <QObject>."
#elif Q_MOC_OUTPUT_REVISION != 67
#error "This file was generated using the moc from 5.12.12. It"
#error "cannot be used with the include files from this version of Qt."
#error "(The moc has changed too much.)"
#endifQT_BEGIN_MOC_NAMESPACE
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
struct qt_meta_stringdata_Widget_t {QByteArrayData data[6];char stringdata0[92];
};
#define QT_MOC_LITERAL(idx, ofs, len) \Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \qptrdiff(offsetof(qt_meta_stringdata_Widget_t, stringdata0) + ofs \- idx * sizeof(QByteArrayData)) \)
static const qt_meta_stringdata_Widget_t qt_meta_stringdata_Widget = {{
QT_MOC_LITERAL(0, 0, 6), // "Widget"
QT_MOC_LITERAL(1, 7, 23), // "on_btnCon_clickedMyself"
QT_MOC_LITERAL(2, 31, 0), // ""
QT_MOC_LITERAL(3, 32, 16), // "on_btnui_clicked"
QT_MOC_LITERAL(4, 49, 21), // "on_pushButton_clicked"
QT_MOC_LITERAL(5, 71, 20) // "on_btnLambda_clicked"},"Widget\0on_btnCon_clickedMyself\0\0""on_btnui_clicked\0on_pushButton_clicked\0""on_btnLambda_clicked"
};
#undef QT_MOC_LITERALstatic const uint qt_meta_data_Widget[] = {// content:8,       // revision0,       // classname0,    0, // classinfo4,   14, // methods0,    0, // properties0,    0, // enums/sets0,    0, // constructors0,       // flags0,       // signalCount// slots: name, argc, parameters, tag, flags1,    0,   34,    2, 0x08 /* Private */,3,    0,   35,    2, 0x08 /* Private */,4,    0,   36,    2, 0x08 /* Private */,5,    0,   37,    2, 0x08 /* Private */,// slots: parametersQMetaType::Void,QMetaType::Void,QMetaType::Void,QMetaType::Void,0        // eod
};void Widget::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{if (_c == QMetaObject::InvokeMetaMethod) {auto *_t = static_cast<Widget *>(_o);Q_UNUSED(_t)switch (_id) {case 0: _t->on_btnCon_clickedMyself(); break;case 1: _t->on_btnui_clicked(); break;case 2: _t->on_pushButton_clicked(); break;case 3: _t->on_btnLambda_clicked(); break;default: ;}}Q_UNUSED(_a);
}QT_INIT_METAOBJECT const QMetaObject Widget::staticMetaObject = { {&QWidget::staticMetaObject,qt_meta_stringdata_Widget.data,qt_meta_data_Widget,qt_static_metacall,nullptr,nullptr
} };const QMetaObject *Widget::metaObject() const
{return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
}void *Widget::qt_metacast(const char *_clname)
{if (!_clname) return nullptr;if (!strcmp(_clname, qt_meta_stringdata_Widget.stringdata0))return static_cast<void*>(this);return QWidget::qt_metacast(_clname);
}int Widget::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{_id = QWidget::qt_metacall(_c, _id, _a);if (_id < 0)return _id;if (_c == QMetaObject::InvokeMetaMethod) {if (_id < 4)qt_static_metacall(this, _c, _id, _a);_id -= 4;} else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {if (_id < 4)*reinterpret_cast<int*>(_a[0]) = -1;_id -= 4;}return _id;
}
QT_WARNING_POP
QT_END_MOC_NAMESPACE

你貼出的這段內容是 Qt 元對象編譯器(moc)自動生成的代碼,具體是 moc_widget.cpp 文件的內容。它是由你的頭文件 widget.h 自動生成的,用于支持 Qt 的信號與槽機制。


📌 這段代碼的作用

這段代碼的主要作用是:

  • 注冊類信息:讓 Qt 知道?Widget?類的存在。
  • 支持信號與槽機制:將你在?.h?文件中聲明的槽函數(slots)綁定到具體的實現上。
  • 元數據管理:包括函數名、參數類型、調用方式等信息。

🔍 逐部分解釋

? 1. 自動生成警告和版本檢查

 

cpp

深色版本

/****************************************************************************
** Meta object code from reading C++ file 'widget.h'
**
** Created by: The Qt Meta Object Compiler version 67 (Qt 5.12.12)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/
  • 這是 moc 自動生成的代碼,不要手動修改!
  • 它基于你的?widget.h?文件生成。
  • 如果你修改了?widget.h?中的類結構(如添加新槽函數),moc 會重新生成這個文件。

? 2. 版本兼容性檢查

 

cpp

深色版本

#include "../../signalAndSlot/widget.h"
#include <QtCore/qbytearray.h>
#include <QtCore/qmetatype.h>
#if !defined(Q_MOC_OUTPUT_REVISION)
#error "The header file 'widget.h' doesn't include <QObject>."
#elif Q_MOC_OUTPUT_REVISION != 67
#error "This file was generated using the moc from 5.12.12. It"
#error "cannot be used with the include files from this version of Qt."
#error "(The moc has changed too much.)"
#endif
  • 檢查是否包含必要的 Qt 基礎類;
  • 檢查 moc 版本是否匹配當前使用的 Qt 版本;
  • 如果版本不一致或缺少?<QObject>,就會報錯。

? 3. 字符串表(方法名)

 

cpp

深色版本

struct qt_meta_stringdata_Widget_t {QByteArrayData data[6];char stringdata0[92];
};
#define QT_MOC_LITERAL(idx, ofs, len) ...

創建一個字符串表,保存所有注冊的方法名稱,比如:

  • "on_btnCon_clickedMyself"
  • "on_pushButton_clicked"

這些名字在運行時會被用來查找對應的槽函數。


? 4. 方法元數據(Meta Data)

 

cpp

深色版本

static const uint qt_meta_data_Widget[] = {// content:8,       // revision0,       // classname0,    0, // classinfo4,   14, // methods...
};

描述類中的方法信息,例如有多少個方法、它們的參數數量、返回類型等。


? 5. 靜態元調用函數(qt_static_metacall)

 

cpp

深色版本

void Widget::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{if (_c == QMetaObject::InvokeMetaMethod) {auto *_t = static_cast<Widget *>(_o);switch (_id) {case 0: _t->on_btnCon_clickedMyself(); break;case 1: _t->on_btnui_clicked(); break;case 2: _t->on_pushButton_clicked(); break;case 3: _t->on_btnLambda_clicked(); break;}}
}
  • 這是一個由 Qt 調用的內部函數;
  • 當某個信號觸發后,Qt 會根據?_id?來決定調用哪一個槽函數;
  • 例如:
  • _id == 2?→ 調用?on_pushButton_clicked()
  • _id == 0?→ 調用?on_btnCon_clickedMyself()

? 6. 注冊元對象(staticMetaObject)

 

cpp

深色版本

QT_INIT_METAOBJECT const QMetaObject Widget::staticMetaObject = { {&QWidget::staticMetaObject,qt_meta_stringdata_Widget.data,qt_meta_data_Widget,qt_static_metacall,nullptr,nullptr
} };
  • 這是 Qt 內部用于識別類信息的核心結構體;
  • 它告訴 Qt:
  • 我這個類是從哪個父類繼承來的;
  • 有哪些槽函數可以響應信號;
  • 如何調用這些函數;

? 7. 輔助函數(metaObject(), qt_metacast(), qt_metacall())

 

cpp

深色版本

const QMetaObject *Widget::metaObject() const { ... }
void *Widget::qt_metacast(const char *_clname) { ... }
int Widget::qt_metacall(QMetaObject::Call _c, int _id, void **_a) { ... }
  • metaObject():獲取當前對象的元對象指針;
  • qt_metacast():用于動態類型轉換(類似?dynamic_cast);
  • qt_metacall():處理元調用(如通過信號觸發槽函數);

?? 錯誤分析:結合你的構建錯誤

你之前遇到的錯誤是:

 

深色版本

undefined reference to `Widget::on_pushButton_clicked()'

而從這段 moc 代碼來看:

 

cpp

深色版本

case 2: _t->on_pushButton_clicked(); break;

說明:

  • Qt?已經知道你需要調用?on_pushButton_clicked()?這個函數
  • 但鏈接器找不到它的定義 →?你沒有在?.cpp?文件中正確定義這個函數

? 解決方案總結

步驟操作
1確保?widget.cpp?中有如下函數定義:
 

cpp

深色版本

void Widget::on_pushButton_clicked()
{std::cout << "UIBTNClicked" << std::endl;
}

| 2 | 清理項目并重新構建: | | - Build → Clean All | | - Build → Run qmake | | - Build → Build All |

| 3 | 檢查 .pro 文件是否包含 widgets 模塊: |

 

qmake

深色版本

QT += core gui widgets

| 4 | 刪除 build 目錄或 debug/release 子目錄,重新構建整個項目。 |


? 小貼士

  • 如果你使用的是 Qt Designer 設計界面,并且按鈕名為?pushButton,那么?on_pushButton_clicked()?是自動綁定的;
  • 如果你改了控件名(如改為?btnPush),但沒改槽函數名,會導致綁定失敗;
  • 使用 Qt5 的連接方式更安全,推薦替代宏寫法:
 

cpp

深色版本

connect(ui->pushButton, &QPushButton::clicked, this, &Widget::on_pushButton_clicked);

如果你愿意貼出完整的 .h.cpp 文件,我可以幫你進一步定位問題。

需要我繼續協助嗎?😊

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//第二種在構造函數中進行槽和信號的綁定//QObject::connect(sender,SIGNAL(signal()),receiver, SLOT(slot()));QObject::connect(ui->btnCon, SIGNAL(clicked()), this, SLOT(on_btnCon_clickedMyself()));//第三方式:lambda表達式:QObject::connect(sender, &Sender::signal, [=]() { /*lambda body */ });QObject::connect(ui->btnLambda, &QPushButton::clicked, [=]() { std::cout << "btnLambdaClicked" << std::endl; });
}Widget::~Widget()
{delete ui;
}void Widget::on_btnCon_clickedMyself()
{std::cout << "btnConClicked" << std::endl;
}void Widget::on_btnui_clicked()
{std::cout << "UIBTNClicked" << std::endl;
}

根據你提供的 widget.cpp 文件內容,看起來你在嘗試使用不同的方式連接信號和槽。不過,從你的描述和代碼來看,問題可能在于缺少對 on_pushButton_clicked() 函數的定義,而這是你在 .h 文件中聲明的一個槽函數。

分析與修正

  1. 確保所有聲明的槽函數都有定義

    • 你提到在構建時遇到了?undefined reference to 'Widget::on_pushButton_clicked()'?的錯誤。
    • 在你提供的?.cpp?文件中并沒有看到?on_pushButton_clicked()?函數的定義。
  2. 添加缺失的槽函數定義

    • 如果你確實需要這個槽函數,請確保在?widget.cpp?中定義它。
  3. 檢查其他槽函數的命名是否正確

    • 確保槽函數名和信號名與?.ui?文件中的控件名一致,或者如果你手動連接信號和槽,則確保連接正確。

修改后的?widget.cpp

以下是基于你提供的代碼進行調整后的版本,包括添加了 on_pushButton_clicked() 函數的定義:

 

cpp

深色版本

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 第二種在構造函數中進行槽和信號的綁定(舊式寫法)QObject::connect(ui->btnCon, SIGNAL(clicked()), this, SLOT(on_btnCon_clickedMyself()));// 使用Qt5的新式寫法(推薦)// 注意:這里假設 ui->btnLambda 和 ui->pushButton 都是有效的控件對象名稱QObject::connect(ui->btnLambda, &QPushButton::clicked, [=]() { std::cout << "btnLambdaClicked" << std::endl; });// 手動連接 pushButton 的點擊事件到 on_pushButton_clicked 槽QObject::connect(ui->pushButton, &QPushButton::clicked, this, &Widget::on_pushButton_clicked);
}Widget::~Widget()
{delete ui;
}// 定義 on_pushButton_clicked 槽函數
void Widget::on_pushButton_clicked()
{std::cout << "UIBTNClicked" << std::endl;
}// 已有的槽函數定義
void Widget::on_btnCon_clickedMyself()
{std::cout << "btnConClicked" << std::endl;
}void Widget::on_btnui_clicked()
{std::cout << "UIBTNClicked" << std::endl;
}

關鍵點

  • 確保所有槽函數都有定義:特別是那些在頭文件中聲明但在實現文件中未定義的函數,如?on_pushButton_clicked
  • 使用 Qt5 推薦的連接方式:相比于舊式的?SIGNAL?和?SLOT?宏,使用函數指針或 Lambda 表達式的方式更加安全且支持編譯期類型檢查。
  • 檢查控件名稱的一致性:確保?.ui?文件中控件的?objectName?屬性與代碼中引用的控件名稱相匹配。

請確認你的 .ui 文件中有名為 pushButton, btnCon, btnLambda 的控件,并且它們的 objectName 設置正確。如果這些控件名稱不正確,你需要相應地調整代碼中的控件引用名稱。

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

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

相關文章

Android音視頻流媒體基礎總結

流媒體開發中&#xff0c;流媒體系統的實現從數據采集、編碼封裝、傳輸分發、接收解碼播放都有哪些技術和實現&#xff0c;流媒體和本地音視頻又有哪些差異&#xff1f; 影像系統開發&#xff0c;流媒體方向和普通的多媒體影像系統開發有一定差異。 相同點在于圖像多媒體處理…

疫菌QBD案例

本文是《A-VAX: Applying Quality by Design to Vaccines》第七個研究的R語言解決方案。 使用帶兩個中心點的二水平析因設計。運行10次實驗。結果是分辨度為III的設計。 A <- c(25,25,15,15,15,25,25,20,15,20) B <- c(12,8,8,12,8,12,8,10,12,10) C <- c(35,15,15…

Linux部署elasticsearch 單機版

Linux部署elasticsearch 1、下載安裝包 Elasticsearch 7.8.0 | Elastic 2、安裝步驟 2.1、上傳安裝包到服務器opt目錄 2.2、解壓 #目錄創建/opt/module cd /opt mkdir module tar -zxvf elasticsearch-7.8.0-linux-x86_64.tar.gz -C /opt/module mv elasticsearch-7.8.0 …

IDEA高效快捷鍵指南

1. 編輯類快捷鍵 編輯快捷鍵是最常用的一類&#xff0c;可以幫助我們快速操作代碼&#xff1a; 快捷鍵 功能描述 Mac Windows 熱度 psvm Tab 生成 main 方法 psvm Tab psvm Tab ????? sout Tab 生成 System.out.println() 輸出語句 sout Tab sout Tab…

【論文寫作參考文獻地址】

參考文獻地址 論文的各種參考文獻地址國家哲學社會科學文獻中心國家科技圖書文獻中心 論文的各種參考文獻地址 國家哲學社會科學文獻中心 資源免費!!! 整體配色就是紅色&#xff0c;主頁輪播有些實時新聞。 博主個人感受&#xff0c;對于計算機類的收錄不是特別的充足 國家科…

華為OD機考-貨幣單位換算-字符串(JAVA 2025B卷)

純暴力解法 import java.util.*; public class ExchangeMoney {public static void main(String[] args) {Scanner scanner new Scanner(System.in);while(scanner.hasNextLine()){int count Integer.parseInt(scanner.nextLine());List<String> strings new ArrayLi…

系統學習·PHP語言

由于之前沒系統的學習PHP語言&#xff0c;都是在做題時遇到不會的才去查&#xff0c;后來發現這樣的效率非常低&#xff0c;審代碼別人一眼掃出漏洞&#xff0c;而我還需要去查一下這行代碼的意思&#xff0c;那個函數的作用&#xff0c;查當然要查&#xff0c;但連簡單的語法都…

leetcode2-兩數相加

leetcode 2 思路 鏈表特性利用&#xff1a;由于數字按逆序存儲&#xff0c;個位在鏈表頭部&#xff0c;因此可以直接從前往后遍歷鏈表進行逐位相加 比如題目中的 2->4->3 和 5->6->4 其實可以直接按位從第一位開始往后相加&#xff0c;就得到啦708 這樣比把數字…

Java的Arrays.sort():排序算法與優化分析

文章目錄 前言一、基本類型數組&#xff1a;雙軸快速排序關鍵優化策略 二、對象數組&#xff1a;TimSort關鍵優化策略 三、性能對比總結總結 前言 在Java中&#xff0c;Arrays.sort()是開發者最常用的排序方法之一。但你是否思考過它的底層實現&#xff1f;本文將基于OpenJDK …

軟件測試質量的“防”與“治”

引言: 想象一下,你正在建造一座摩天大樓。你是愿意在打地基時就嚴格檢查材料規格和設計圖紙(主動防患),還是等到大樓封頂后才開始拿著錘子敲敲打打找裂縫(被動補救)?軟件世界亦是如此!今天,我們就來聊聊軟件測試這個“質量守護神”的兩大戰略思維和三大實戰招式,讓你…

TDengine 如何從 2.x 遷移到 3.0

本節講述如何通過 Explorer 界面創建數據遷移任務&#xff0c;從舊版 TDengine2 遷移數據到 TDengine 3.0 集群。 功能概述 taosX 通過 SQL 查詢源集群數據&#xff0c;并把查詢結果寫入到目標數據庫。具體實現上&#xff0c;taosX 以一個子表的一個時間段的數據作為查詢的基…

免下載蘋果 IPA 文件重簽名工具:快速更換應用名稱和 BID的教程

在iOS設備的使用和開發過程中&#xff0c;我們有時需要對IPA文件進行重簽名&#xff0c;以便更換應用名稱、Bundle ID&#xff08;軟件包標識符&#xff09;或其他相關信息。這一過程通常需要使用到特定的工具&#xff0c;然而&#xff0c;市面上的一些工具可能需要下載和安裝&…

Python全棧開發:前后端分離項目架構詳解

文章目錄 技術棧選擇后端技術棧前端技術棧 項目整體結構詳細目錄結構說明后端架構&#xff08;backend/&#xff09;1. 應用核心&#xff08;app/&#xff09;2. 數據層&#xff08;models/&#xff09;3. API模式層&#xff08;schemas/&#xff09;4. API路由層&#xff08;a…

微信小程序使用圖片實現紅包雨功能

微信小程序紅包雨功能實現&#xff1a;從組件封裝到頁面調用的完整實踐 先看示例截圖&#xff1a; 一、背景與技術選型 在微信小程序營銷活動中&#xff0c;紅包雨是一種極具吸引力的互動形式。實現紅包雨效果主要有 Canvas 和圖片兩種方案&#xff1a; &#xff08;1&…

Python day31

浙大疏錦行 數據拆分的基本框架&#xff0c;拆分后讓項目結構更加清晰

Chapter10-XXE

文章目錄 1.XXE介紹1.1 XXE產生的原因1.1.1 什么是XML&#xff1f;1.1.2 什么是XML實體1.1.3 什么是文檔類型定義&#xff08;document type definition&#xff09;1.1.4 什么是XML自定義實體1.1.5 什么是XML外部實體 2.XXE攻擊類型2.1 利用XXE檢索文件2.2 利用XXE執行SSRF攻擊…

Ribbon負載均衡實戰指南:7種策略選擇與生產避坑

引言&#xff1a;客戶端負載均衡的不可替代性 當面試官問你&#xff1a;“Ribbon 和 Nginx 有什么區別&#xff1f;”——Ribbon 是進程內 LB 這一句話值 20K 月薪。 作為微服務調用的核心樞紐&#xff0c;Ribbon 通過 ??本地服務清單動態分發請求??&#xff0c;避免中心化…

Webpack:現代前端構建工具的核心解析

Hi&#xff0c;我是布蘭妮甜 &#xff01;在前端工程化日益重要的今天&#xff0c;Webpack作為主流構建工具&#xff0c;已成為現代前端開發的核心基礎設施。它通過模塊化打包機制&#xff0c;優雅地解決了復雜應用中的資源管理問題&#xff0c;使開發者能夠專注于業務邏輯的實…

Elasticsearch索引wildcard查詢

在之前的文章 Elasticsearch索引的字段映射 中介紹過關于索引中字段查詢的多種方式。可以根據需要通過設置索引字段的type以及fields來實現分詞,精確匹配等多種方式的查詢。 elasticSearch中檢索核心類型大概可以分為:精準匹配檢索(Term-level queries)和基于分詞的全文匹…

1.3、SDH光接口類型

接口類型的命名遵循一個特定的代碼結構&#xff0c;格式通常為&#xff1a;應用代碼-速率等級.波長/距離代碼。 代碼的第一位字母表示應用場合&#xff1a;I 表示局內通信&#xff1b;S 表示短距離局間通信&#xff1b;L 表示長距離局間通信。字母橫杠后的第一位表示 STM 的速率…