主旨:本文主要是为了还原QT链接信号槽的真相
开发环境
qt 4.5.2
这是在是一个入门级的小问题
如果草函数声明时没有像这样指明:
public slots: 并且槽函数没有声明为虚函数,则会产生链接失败,否则无法响应。为什么呢?先将各处看起来搞得混淆难懂的角落曝光再说。
Q_OBJECT展开
1 public:
2 template <typename T> inline
3 void qt_check_for_QOBJECT_macro(const T &_q_argument) const
4 { int i = qYouForgotTheQ_OBJECT_Macro(this, &_q_argument); i = i; }
5 static const QMetaObject staticMetaObject; virtual const QMetaObject *metaObject() const; virtual void *qt_metacast(const char *);
6 static inline QString tr(const char *s, const char *c = 0)
7 { return staticMetaObject.tr(s, c); }
8 static inline QString trUtf8(const char *s, const char *c = 0)
9 { return staticMetaObject.trUtf8(s, c); }
10 static inline QString tr(const char *s, const char *c, int n)
11 { return staticMetaObject.tr(s, c, n); }
12 static inline QString trUtf8(const char *s, const char *c, int n)
13 { return staticMetaObject.trUtf8(s, c, n); }
14 virtual int qt_metacall(QMetaObject::Call, int, void **);
15
16 private:
17 Ui::TestQtDlgClass展开
1class Ui_TestQtDlgClass
2{
3public:
4 QWidget *widget;
5 QHBoxLayout *horizontalLayout;
6 QPushButton *pushButton;
7 QPushButton *pushButton_2;
8 QPushButton *pushButton_3;
9
10 void setupUi(QDialog *TestQtDlgClass)
11 {
12 if (TestQtDlgClass->objectName().isEmpty())
13 TestQtDlgClass->setObjectName(QString::fromUtf8("TestQtDlgClass"));
14 TestQtDlgClass->resize(600, 400);
15 widget = new QWidget(TestQtDlgClass);
16 widget->setObjectName(QString::fromUtf8("widget"));
17 widget->setGeometry(QRect(50, 100, 245, 27));
18 horizontalLayout = new QHBoxLayout(widget);
19 horizontalLayout->setSpacing(6);
20 horizontalLayout->setMargin(11);
21 horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout"));
22 horizontalLayout->setContentsMargins(0, 0, 0, 0);
23 pushButton = new QPushButton(widget);
24 pushButton->setObjectName(QString::fromUtf8("pushButton"));
25
26 horizontalLayout->addWidget(pushButton);
27
28 pushButton_2 = new QPushButton(widget);
29 pushButton_2->setObjectName(QString::fromUtf8("pushButton_2"));
30
31 horizontalLayout->addWidget(pushButton_2);
32
33 pushButton_3 = new QPushButton(widget);
34 pushButton_3->setObjectName(QString::fromUtf8("pushButton_3"));
35
36 horizontalLayout->addWidget(pushButton_3);
37
38
39 retranslateUi(TestQtDlgClass);
40 QObject::connect(pushButton, qFlagLocation("2""clicked()" "\0""e:\\DEVELOP\\TEST\\TestQtDlg\\GeneratedFiles\\ui_testqtdlg.h"":""64"), TestQtDlgClass, qFlagLocation("1""button1()" "\0""e:\\DEVELOP\\TEST\\TestQtDlg\\GeneratedFiles\\ui_testqtdlg.h"":""64"));
41 QObject::connect(pushButton_2, qFlagLocation("2""clicked()" "\0""e:\\DEVELOP\\TEST\\TestQtDlg\\GeneratedFiles\\ui_testqtdlg.h"":""65"), TestQtDlgClass, qFlagLocation("1""button2()" "\0""e:\\DEVELOP\\TEST\\TestQtDlg\\GeneratedFiles\\ui_testqtdlg.h"":""65"));
42 QObject::connect(pushButton_3, qFlagLocation("2""clicked()" "\0""e:\\DEVELOP\\TEST\\TestQtDlg\\GeneratedFiles\\ui_testqtdlg.h"":""66"), TestQtDlgClass, qFlagLocation("1""button3()" "\0""e:\\DEVELOP\\TEST\\TestQtDlg\\GeneratedFiles\\ui_testqtdlg.h"":""66"));
43
44 QMetaObject::connectSlotsByName(TestQtDlgClass);
45 }
46
47 void retranslateUi(QDialog *TestQtDlgClass)
48 {
49 TestQtDlgClass->setWindowTitle(QApplication::translate("TestQtDlgClass", "TestQtDlg", 0, QApplication::UnicodeUTF8));
50 pushButton->setText(QApplication::translate("TestQtDlgClass", "PushButton", 0, QApplication::UnicodeUTF8));
51 pushButton_2->setText(QApplication::translate("TestQtDlgClass", "PushButton", 0, QApplication::UnicodeUTF8));
52 pushButton_3->setText(QApplication::translate("TestQtDlgClass", "PushButton", 0, QApplication::UnicodeUTF8));
53 (void)TestQtDlgClass;;
54 }
55
56};这里进行信号槽链接:
QObject::connect(pushButton, qFlagLocation("2""clicked()" "\0""e:\\DEVELOP\\TEST\\TestQtDlg\\GeneratedFiles\\ui_testqtdlg.h"":""64"), TestQtDlgClass, qFlagLocation("1""button1()" "\0""e:\\DEVELOP\\TEST\\TestQtDlg\\GeneratedFiles\\ui_testqtdlg.h"":""64"));
flagged_locations代码
1const int flagged_locations_count = 2;
2static const char* flagged_locations[flagged_locations_count] = {0};
3
4const char *qFlagLocation(const char *method)
5{
6 static int idx = 0;
7 flagged_locations[idx] = method;
8 idx = (idx+1) % flagged_locations_count;
9 return method;
10}
11
QObject::connect原始文件
QObject::connect
1/**//*!
2 \threadsafe
3
4 Creates a connection of the given \a type from the \a signal in
5 the \a sender object to the \a method in the \a receiver object.
6 Returns true if the connection succeeds; otherwise returns false.
7
8 You must use the \c SIGNAL() and \c SLOT() macros when specifying
9 the \a signal and the \a method, for example:
10
11 \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 22
12
13 This example ensures that the label always displays the current
14 scroll bar value. Note that the signal and slots parameters must not
15 contain any variable names, only the type. E.g. the following would
16 not work and return false:
17
18 \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 23
19
20 A signal can also be connected to another signal:
21
22 \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 24
23
24 In this example, the \c MyWidget constructor relays a signal from
25 a private member variable, and makes it available under a name
26 that relates to \c MyWidget.
27
28 A signal can be connected to many slots and signals. Many signals
29 can be connected to one slot.
30
31 If a signal is connected to several slots, the slots are activated
32 in an arbitrary order when the signal is emitted.
33
34 The function returns true if it successfully connects the signal
35 to the slot. It will return false if it cannot create the
36 connection, for example, if QObject is unable to verify the
37 existence of either \a signal or \a method, or if their signatures
38 aren't compatible.
39
40 For every connection you make, a signal is emitted; two signals are emitted
41 for duplicate connections. You can break all of these connections with a
42 single disconnect() call.
43
44 The optional \a type parameter describes the type of connection
45 to establish. In particular, it determines whether a particular
46 signal is delivered to a slot immediately or queued for delivery
47 at a later time. If the signal is queued, the parameters must be
48 of types that are known to Qt's meta-object system, because Qt
49 needs to copy the arguments to store them in an event behind the
50 scenes. If you try to use a queued connection and get the error
51 message
52
53 \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 25
54
55 call qRegisterMetaType() to register the data type before you
56 establish the connection.
57
58 \sa disconnect(), sender(), qRegisterMetaType()
59*/
60
61bool QObject::connect(const QObject *sender, const char *signal,
62 const QObject *receiver, const char *method,
63 Qt::ConnectionType type)
64{
65 {
66 const void *cbdata[] = { sender, signal, receiver, method, &type };
67 if (QInternal::activateCallbacks(QInternal::ConnectCallback, (void **) cbdata))
68 return true;
69 }
70
71#ifndef QT_NO_DEBUG
72 bool warnCompat = true;
73#endif
74 if (type == Qt::AutoCompatConnection) {
75 type = Qt::AutoConnection;
76#ifndef QT_NO_DEBUG
77 warnCompat = false;
78#endif
79 }
80
81 if (sender == 0 || receiver == 0 || signal == 0 || method == 0) {
82 qWarning("QObject::connect: Cannot connect %s::%s to %s::%s",
83 sender ? sender->metaObject()->className() : "(null)",
84 (signal && *signal) ? signal+1 : "(null)",
85 receiver ? receiver->metaObject()->className() : "(null)",
86 (method && *method) ? method+1 : "(null)");
87 return false;
88 }
89 QByteArray tmp_signal_name;
90
91 if (!check_signal_macro(sender, signal, "connect", "bind"))
92 return false;
93 const QMetaObject *smeta = sender->metaObject();
94 const char *signal_arg = signal;
95 ++signal; //skip code
96 int signal_index = smeta->indexOfSignal(signal);
97 if (signal_index < 0) {
98 // check for normalized signatures
99 tmp_signal_name = QMetaObject::normalizedSignature(signal - 1);
100 signal = tmp_signal_name.constData() + 1;
101
102 signal_index = smeta->indexOfSignal(signal);
103 if (signal_index < 0) {
104 err_method_notfound(sender, signal_arg, "connect");
105 err_info_about_objects("connect", sender, receiver);
106 return false;
107 }
108 }
109
110 QByteArray tmp_method_name;
111 int membcode = extract_code(method);
112
113 if (!check_method_code(membcode, receiver, method, "connect"))
114 return false;
115 const char *method_arg = method;
116 ++method; // skip code
117
118 const QMetaObject *rmeta = receiver->metaObject();
119 int method_index = -1;
120 switch (membcode) {
121 case QSLOT_CODE:
122 method_index = rmeta->indexOfSlot(method);
123 break;
124 case QSIGNAL_CODE:
125 method_index = rmeta->indexOfSignal(method);
126 break;
127 }
128 if (method_index < 0) {
129 // check for normalized methods
130 tmp_method_name = QMetaObject::normalizedSignature(method);
131 method = tmp_method_name.constData();
132 switch (membcode) {
133 case QSLOT_CODE:
134 method_index = rmeta->indexOfSlot(method);
135 break;
136 case QSIGNAL_CODE:
137 method_index = rmeta->indexOfSignal(method);
138 break;
139 }
140 }
141
142 if (method_index < 0) {
143 err_method_notfound(receiver, method_arg, "connect");
144 err_info_about_objects("connect", sender, receiver);
145 return false;
146 }
147 if (!QMetaObject::checkConnectArgs(signal, method)) {
148 qWarning("QObject::connect: Incompatible sender/receiver arguments"
149 "\n %s::%s --> %s::%s",
150 sender->metaObject()->className(), signal,
151 receiver->metaObject()->className(), method);
152 return false;
153 }
154
155 int *types = 0;
156 if ((type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
157 && !(types = queuedConnectionTypes(smeta->method(signal_index).parameterTypes())))
158 return false;
159
160#ifndef QT_NO_DEBUG
161 {
162 QMetaMethod smethod = smeta->method(signal_index);
163 QMetaMethod rmethod = rmeta->method(method_index);
164 if (warnCompat) {
165 if(smethod.attributes() & QMetaMethod::Compatibility) {
166 if (!(rmethod.attributes() & QMetaMethod::Compatibility))
167 qWarning("QObject::connect: Connecting from COMPAT signal (%s::%s)", smeta->className(), signal);
168 } else if(rmethod.attributes() & QMetaMethod::Compatibility && membcode != QSIGNAL_CODE) {
169 qWarning("QObject::connect: Connecting from %s::%s to COMPAT slot (%s::%s)",
170 smeta->className(), signal, rmeta->className(), method);
171 }
172 }
173 }
174#endif
175 QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);
176 const_cast<QObject*>(sender)->connectNotify(signal - 1);
177 return true;
178}
179