Qt信號之自定義數據類型


【1】為什么需要自定義數據類型?

內置類型畢竟很有局限性,否則為什么還需要類呢。總之,有時候,我們多么希望信號能發送自定義數據類型。

幸哉~ Qt是支持自定義信號,且自定義信號可以發送自定義數據類型的對象。

【2】使用方法(聲明 和 注冊自定義數據類型)

1)引入頭文件:#include<QMetaType>

2)添加聲明:利用宏 Q_DECLARE_METATYPE

3)注冊:利用方法 qRegisterMetaType

【3】實例Demo

1.文件目錄(為了更好的模擬現實項目的需求,示例程序邏輯比較復雜

2.pro文件

 1 #-------------------------------------------------
 2 #
 3 # Project created by QtCreator 2017-06-27T21:34:46
 4 #
 5 #-------------------------------------------------
 6 
 7 QT       += core gui
 8 
 9 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
10 
11 TARGET = CustomDataType
12 TEMPLATE = app
13 
14 DEFINES += QT_DEPRECATED_WARNINGS
15 
16 SOURCES += main.cpp\
17     MyDialog.cpp \
18     MainWindow.cpp
19 
20 HEADERS  += \
21     MyDialog.h \
22     MainWindow.h
23 
24 FORMS    += \
25     MyDialog.ui \
26     MainWindow.ui

3.MyDialog.h(自定義數據類型CustomDataType,使用宏Q_DECLARE_METATYPE聲明數據類型

 1 #ifndef MYDIALOG_H
 2 #define MYDIALOG_H
 3 
 4 #include <QDialog>
 5 #include <QMetaType>
 6 
 7 namespace Ui
 8 {
 9     class MyDialog;
10 }
11 
12 class CustomDataType
13 {
14 public:
15     CustomDataType(int n = 100) : m_nValue(n) {}
16     ~CustomDataType() {}
17     int getValue() const { return m_nValue; }
18     void setValue(int nValue) { m_nValue = nValue; }
19 
20 private:
21     int m_nValue;
22 };
23 
24 class MyDialog : public QDialog
25 {
26     Q_OBJECT
27 
28 public:
29     explicit MyDialog(QWidget *parent = 0);
30     ~MyDialog();
31 
32 public slots:
33     void onTextChanged(const QString &str);
34 
35 signals:
36     void postData(const CustomDataType &data);
37 
38 protected:
39     void closeEvent(QCloseEvent *event);
40 
41 private:
42     Ui::MyDialog *m_pUI;
43     CustomDataType m_data;
44 };
45 
46 Q_DECLARE_METATYPE(CustomDataType)
47 
48 #endif // MYDIALOG_H

4.MyDialog.cpp(構造函數中利用qRegisterMetaType注冊自定義數據類型

 1 #include "MyDialog.h"
 2 #include "ui_MyDialog.h"
 3 
 4 MyDialog::MyDialog(QWidget *parent) :
 5     QDialog(parent),
 6     m_pUI(new Ui::MyDialog)
 7 {
 8     m_pUI->setupUi(this);
 9     qRegisterMetaType<CustomDataType>("CustomDataType");
10 
11     connect(m_pUI->lineEdit, &QLineEdit::textChanged, this, &MyDialog::onTextChanged);
12 }
13 
14 MyDialog::~MyDialog()
15 {
16     if (m_pUI)
17     {
18         delete m_pUI;
19         m_pUI = Q_NULLPTR;
20     }
21 }
22 
23 void MyDialog::closeEvent(QCloseEvent *event)
24 {
25     emit postData(m_data);
26     QDialog::closeEvent(event);
27 }
28 
29 void MyDialog::onTextChanged(const QString & str)
30 {
31     bool bOK = false;
32     int nNumber = str.toInt(&bOK);
33     bOK ? m_data.setValue(nNumber) : m_data.setValue(-1);
34 }

5.MainWindow.h(業務類中直接定義槽函數,利用自定義數據類型作為參數類型即可

 1 #ifndef MAINWINDOW_H
 2 #define MAINWINDOW_H
 3 
 4 #include <QDebug>
 5 #include <QMainWindow>
 6 #include "MyDialog.h"
 7 
 8 namespace Ui
 9 {
10     class MainWindow;
11 }
12 
13 class MainWindow : public QMainWindow
14 {
15     Q_OBJECT
16 
17 public:
18     explicit MainWindow(QWidget *parent = 0);
19     ~MainWindow();
20 
21 public slots:
22     void onPostData(const CustomDataType &data);
23     void onPushButtonPress();
24 
25 private:
26     MyDialog m_dialog;
27     Ui::MainWindow *m_pUI;
28 };
29 
30 #endif // MAINWINDOW_H

6.MainWindow.cpp(connect正常連接信號與槽,並定義槽函數

 1 #include "MainWindow.h"
 2 #include "ui_mainwindow.h"
 3 
 4 MainWindow::MainWindow(QWidget *parent)
 5     : QMainWindow(parent)
 6     , m_pUI(new Ui::MainWindow)
 7 {
 8     m_pUI->setupUi(this);
 9     connect(&m_dialog, &MyDialog::postData, this, &MainWindow::onPostData);
10     connect(m_pUI->pushButton, &QPushButton::pressed, this, &MainWindow::onPushButtonPress);
11 }
12 
13 MainWindow::~MainWindow()
14 {
15     if (m_pUI)
16     {
17         delete m_pUI;
18         m_pUI = Q_NULLPTR;
19     }
20 }
21 
22 void MainWindow::onPostData(const CustomDataType &data)
23 {
24     m_pUI->pushButton->setText(QString::number(data.getValue()));
25 }
26 
27 void MainWindow::onPushButtonPress()
28 {
29     m_dialog.show();
30 }

7.main.cpp

 1 #include "MainWindow.h"
 2 #include <QApplication>
 3 
 4 int main(int argc, char *argv[])
 5 {
 6     QApplication a(argc, argv);
 7     MainWindow w;
 8     w.show();
 9 
10     return a.exec();
11 }

8.ui文件請自理。

【4】運行效果圖

按順序圖1->圖2->圖3

圖1:彈出主窗體,主窗體中央部位放置一個PushButton,點擊PushButton后,彈出圖2對話框。

圖2:對話框中間放置一個LineEdit,編輯數值123456,然后關閉對話框。

圖3:當圖2對話框被關閉時,會發送信號,信號會附加自定義數據類型的數據對象。

主窗體的響應槽函數從自定義數據對象中獲取值,然后刷新PushButton文本為設置的數據值。

【5】源碼剖析

1)宏 Q_DECLARE_METATYPE

源碼如下。摘自版本路徑(C:\Qt\Qt5.7.1\5.7\msvc2013\include\QtCore\qmetatype.h)

 1 #define Q_DECLARE_METATYPE(TYPE) Q_DECLARE_METATYPE_IMPL(TYPE)
 2 #define Q_DECLARE_METATYPE_IMPL(TYPE)                                   \
 3     QT_BEGIN_NAMESPACE                                                  \
 4     template <>                                                         \
 5     struct QMetaTypeId< TYPE >                                          \
 6     {                                                                   \
 7         enum { Defined = 1 };                                           \
 8         static int qt_metatype_id()                                     \
 9             {                                                           \
10                 static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
11                 if (const int id = metatype_id.loadAcquire())           \
12                     return id;                                          \
13                 const int newId = qRegisterMetaType< TYPE >(#TYPE,      \
14                               reinterpret_cast< TYPE *>(quintptr(-1))); \
15                 metatype_id.storeRelease(newId);                        \
16                 return newId;                                           \
17             }                                                           \
18     };                                                                  \
19     QT_END_NAMESPACE
20 
21 #ifndef Q_BASIC_ATOMIC_INITIALIZER
22 #  define Q_BASIC_ATOMIC_INITIALIZER(a) { (a) }
23 #endif

2) 模板函數qRegisterMetaType

源碼如下。摘自版本路徑(C:\Qt\Qt5.7.1\5.7\msvc2013\include\QtCore\qmetatype.h)

 1 template <typename T>
 2 int qRegisterMetaType(const char *typeName
 3 #ifndef Q_QDOC
 4     , T * dummy = Q_NULLPTR
 5     , typename QtPrivate::MetaTypeDefinedHelper<T, QMetaTypeId2<T>::Defined && !QMetaTypeId2<T>::IsBuiltIn>::DefinedType defined = 
 6         QtPrivate::MetaTypeDefinedHelper<T, QMetaTypeId2<T>::Defined && !QMetaTypeId2<T>::IsBuiltIn>::Defined
 7 #endif
 8 )
 9 {
10 #ifdef QT_NO_QOBJECT
11     QT_PREPEND_NAMESPACE(QByteArray) normalizedTypeName = typeName;
12 #else
13     QT_PREPEND_NAMESPACE(QByteArray) normalizedTypeName = QMetaObject::normalizedType(typeName);
14 #endif
15     return qRegisterNormalizedMetaType<T>(normalizedTypeName, dummy, defined);
16 }
17 
18 template<typename T, bool defined>
19 struct MetaTypeDefinedHelper
20 {
21     enum DefinedType { Defined = defined };
22 };
23 
24 template <typename T>
25 int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName
26 #ifndef Q_QDOC
27     , T * dummy = 0
28     , typename QtPrivate::MetaTypeDefinedHelper<T, QMetaTypeId2<T>::Defined && !QMetaTypeId2<T>::IsBuiltIn>::DefinedType defined = 
29         QtPrivate::MetaTypeDefinedHelper<T, QMetaTypeId2<T>::Defined && !QMetaTypeId2<T>::IsBuiltIn>::Defined
30 #endif
31 )
32 {
33 #ifndef QT_NO_QOBJECT
34     Q_ASSERT_X(normalizedTypeName == QMetaObject::normalizedType(normalizedTypeName.constData()), 
35                "qRegisterNormalizedMetaType", 
36                "qRegisterNormalizedMetaType was called with a not normalized type name, please call qRegisterMetaType instead.");
37 #endif
38     const int typedefOf = dummy ? -1 : QtPrivate::QMetaTypeIdHelper<T>::qt_metatype_id();
39     if (typedefOf != -1)
40         return QMetaType::registerNormalizedTypedef(normalizedTypeName, typedefOf);
41 
42     QMetaType::TypeFlags flags(QtPrivate::QMetaTypeTypeFlags<T>::Flags);
43 
44     if (defined)
45         flags |= QMetaType::WasDeclaredAsMetaType;
46 
47     const int id = QMetaType::registerNormalizedType(normalizedTypeName,
48                                    QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Destruct,
49                                    QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Construct,
50                                    int(sizeof(T)),
51                                    flags,
52                                    QtPrivate::MetaObjectForType<T>::value());
53 
54     if (id > 0) 
55     {
56         QtPrivate::SequentialContainerConverterHelper<T>::registerConverter(id);
57         QtPrivate::AssociativeContainerConverterHelper<T>::registerConverter(id);
58         QtPrivate::MetaTypePairHelper<T>::registerConverter(id);
59         QtPrivate::MetaTypeSmartPointerHelper<T>::registerConverter(id);
60     }
61 
62     return id;
63 }

詳細內容。

Good Good Study,Day Day Up.

順序 選擇 循環 總結

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM