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.
顺序 选择 循环 总结