QT之靜態函數發送訊號
一、簡介
由於部落客本人是初學者對QT的機制不了解,所以遇到了一個比較大的坑,特此記錄一下。我遇到的問題是無法在靜態函數中向另外一個類發送訊號。解決辦法:先將訊號發送給同類中的普通函數,然後在從普通函數中發送訊號給外部類。
二、C與C++中static的用法
這裡不是介紹QT靜態函數訊號的發送嗎,和static的用法有什麼聯繫,因為在編寫程式碼中會出現靜態成員無法訪問普通成員的錯誤,這裡我複製了菜鳥教程的圖片。
接下來先了解一下static的用法。
- C語言中static的作用
主要有三個作用:隱藏性、持久性、默認值為0
- 隱藏性:當我們同時編譯多個文件時,所有未加 static 前綴的全局變數和函數都具有全局可見性。
- 持久性:在函數內部使用static修飾變數時,不僅可以是變數具有隱藏性,還能增加變數生命。
- 默認初始化為 0:在靜態數據區,記憶體中所有的位元組默認值都是 0x00,其實全局變數也具備這一屬性,因為全局變數也存儲在靜態數據區。
想了解具體的用法可以去菜鳥教程學習《C 語言中 static 的作用》。
- C++ 中static的作用
C++中使用static需要主要的地方
- 靜態成員函數中不能調用非靜態成員。
- 非靜態成員函數中可以調用靜態成員。因為靜態成員屬於類本身,在類的對象產生之前就已經存在了,所以在非靜態成員函數中是可以調用靜態成員的。
- 靜態成員變數使用前必須先初始化(如 int MyClass::m_nNumber = 0;),否則會在 linker 時出錯。
修飾成員變數
- 靜態數據成員可以實現多個對象之間的數據共享,它是類的所有對象的共享成員,它在記憶體中只佔一份空間,如果改變它的值,則各對象中這個數據成員的值都被改變。
- 靜態數據成員是在程式開始運行時被分配空間,到程式結束之後才釋放,只要類中指定了靜態數據成員,即使不定義對象,也會為靜態數據成員分配空間。
- 靜態數據成員可以被初始化,但是只能在類體外進行初始化,若未對靜態數據成員賦初值,則編譯器會自動為其初始化為 0。
- 靜態數據成員既可以通過對象名引用,也可以通過類名引用。
修飾成員函數
- 靜態成員函數和靜態數據成員一樣,他們都屬於類的靜態成員,而不是對象成員。
- 非靜態成員函數有 this 指針,而靜態成員函數沒有 this 指針。
- 靜態成員函數主要用來方位靜態數據成員而不能訪問非靜態成員。
想了解具體的用法可以去菜鳥教程學習《C/C++ 中 static 的用法全局變數與局部變數》。
三、程式源碼
ClassA.h 文件
#ifndef CLASSA_H
#define CLASSA_H
#include <QObject>
#include <iostream>
class ClassA : public QObject
{
Q_OBJECT
public:
ClassA();
~ClassA();
static void SignalGeneration(); //靜態函數,訊號將從此函數發生
private:
static ClassA *myClassA; //它在記憶體中只佔一份空間
signals:
void SigExternal(QString str); //向外部的類發送訊號
void SigInsideDelier(char *str); //發送訊號到此類的訊號槽
private slots:
void SlotInsideDelier(char *str); //內部槽 用於響應內部訊號
};
#endif // CLASSA_H
ClassA.cpp文件
#include "ClassA.h"
ClassA *ClassA::myClassA = NULL; // 靜態成員變數使用前必須先初始化,否則使用是會提示變數未定義
ClassA::ClassA()
{
myClassA = this;
connect(this, &ClassA::SigInsideDelier, [this](char *str)
{
emit SlotInsideDelier(str);
});
}
void ClassA::SignalGeneration()
{
const char *str = "訊號生產成功";
emit myClassA->SigInsideDelier((char *)str);
}
void ClassA::SlotInsideDelier(char *str)
{
emit SigExternal(QString(str));
}
ClassA::~ClassA()
{
}
widget.h文件
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include "ClassA.h"
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_pushButton_clicked();
void classA_msg(QString str);
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
widget.cpp文件
#include "widget.h"
#include "ui_widget.h"
#include <iostream>
#include "ClassA.h"
using namespace std;
ClassA *classA;
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
classA = new ClassA();
connect(classA, SIGNAL(SigExternal(QString)), this, SLOT(classA_msg(QString))); //注意這裡傳遞訊號必須使用QString不能使用char *,否則接收數據會異常,具體原因未知
ui->setupUi(this);
}
Widget::~Widget()
{
delete classA;
delete ui;
}
void Widget::on_pushButton_clicked()
{
ClassA::SignalGeneration();
}
void Widget::classA_msg(QString str)
{
ui->plainTextEdit->appendPlainText(str);
}
程式介面
四、運行測試
參考文獻
C 語言中 static 的作用://www.runoob.com/w3cnote/c-static-effect.html
C/C++ 中 static 的用法全局變數與局部變數://www.runoob.com/w3cnote/cpp-static-usage.html
Qt知識點梳理 —— 靜態函數發送訊號://blog.csdn.net/tingzhiyi/article/details/112631489