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.

顺序 选择 循环 总结

 

posted @ 2017-06-27 22:47  kaizenly  阅读(12200)  评论(0编辑  收藏  举报
打赏