Details
-
Bug
-
Resolution: Unresolved
-
P2: Important
-
6.8.3
-
None
Description
When enabling definitions of properties, signals, etc. using `TEST_EXIST_FOR_TEST_NG` defined by `__has_include` as follows, the following issues.
- Properties or signals cannot be used from QML.
- When using `SIGNAL` or `SLOT` in QObject::connect, the target function cannot use.
- testNG.h
#ifndef TESTNG_H #define TESTNG_H #include <QDebug> #if __has_include("test.h") #include "test.h" #define TEST_EXIST_FOR_TEST_NG #endif class TestNG : public QObject { Q_OBJECT #ifdef TEST_EXIST_FOR_TEST_NG Q_PROPERTY(int num READ num WRITE setNum NOTIFY numChanged) #endif // TEST_EXIST_FOR_TEST_NG public: TestNG() : QObject(nullptr) {} #ifdef TEST_EXIST_FOR_TEST_NG TestNG(Test *test) : QObject(nullptr) , mTest(test) { qDebug() << static_cast<bool>( QObject::connect( mTest, SIGNAL(numChanged()), this, SLOT(slotTest()))); } int num() const { return mNum; } signals: void numChanged(); void calledSlotTest(); public slots: void setNum(const int &nNum) { if (nNum != mNum) { mNum = nNum; emit numChanged(); } } void slotTest() { qDebug() << __FUNCTION__; emit calledSlotTest(); } private: Test *mTest; protected: int mNum = 0; #endif // TEST_EXIST_FOR_TEST_NG }; #endif // TESTNG_H
- test.h
#ifndef TEST_H #define TEST_H #include <QObject> #include <QDebug> class Test : public QObject { Q_OBJECT Q_PROPERTY(int num READ num WRITE setNum NOTIFY numChanged) public: Test() : QObject(nullptr) {} int num() const { return mNum; } signals: void numChanged(); void calledSlotTest(); public slots: void setNum(const int &nNum) { if (nNum != mNum) { mNum = nNum; emit numChanged(); } } void slotTest() { qDebug() << __FUNCTION__; emit calledSlotTest(); } protected: int mNum = 0; }; #endif // TEST_H
- main.cpp
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include "test.h" #include "testNG.h" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQmlApplicationEngine engine; Test testObj; engine.rootContext()->setContextProperty("Test", &testObj); #ifdef TEST_EXIST_FOR_TEST_NG TestNG testNGObj(&testObj); #else TestNG testNGObj(); #endif // TEST_EXIST_FOR_TEST_NG engine.rootContext()->setContextProperty("TestNG", &testNGObj); QObject::connect( &engine, &QQmlApplicationEngine::objectCreationFailed, &app, []() { QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.loadFromModule("Main", "Main"); return app.exec(); }
- Main.qml
import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQml.Models import Main Window { id: root objectName: "Main.qml" width: 640 height: 480 visible: true title: qsTr("Main") property ObjectModel testModel: ObjectModel { Component.onCompleted: { root.testModel.append(Test) root.testModel.append(TestNG) } } ScrollView { anchors.fill: parent ColumnLayout { Repeater { id: contentsRepeater model: root.testModel.count delegate: RowLayout { id: contentsRepeaterDelegate required property int index readonly property var target: root.testModel.get(index) Text { text: "" + contentsRepeaterDelegate.target } GridLayout { columns: 2 Text { text: "num" } Text { text: contentsRepeaterDelegate.target.num } Button { Layout.columnSpan: 2 text: "num count up" onReleased: { contentsRepeaterDelegate.target.num = contentsRepeaterDelegate.target.num + 1; } } Text { text: "onNumChangedTime" } Text { id: onNumChangedTimeText } Text { text: "onCalledSlotTestTime" } Text { id: onCalledSlotTestTimeText } Connections { target: contentsRepeaterDelegate.target function onNumChanged() { onNumChangedTimeText.text = new Date().toLocaleTimeString(Qt.locale(), "hh:mm:ss.zzz") } function onCalledSlotTest() { onCalledSlotTestTimeText.text = new Date().toLocaleTimeString(Qt.locale(), "hh:mm:ss.zzz") } } } } } } } }
The following warning will be displayed when executed.
2025-04-21 17:19:27.269 [37532] [21912] [warning] [qt.core.qobject.connect] - QObject::connect: No such slot TestNG::slotTest() in C:\work\projects\JVC\git\cannot-connect-to-slot\main\testNG.h:31 2025-04-21 17:19:27.879 [37532] [21912] [warning] [default] - QML Connections: Detected function "onNumChanged" in Connections element. This is probably intended to be a signal handler but no signal of the target matches the name. 2025-04-21 17:19:27.879 [37532] [21912] [warning] [default] - QML Connections: Detected function "onCalledSlotTest" in Connections element. This is probably intended to be a signal handler but no signal of the target matches the name. 2025-04-21 17:19:27.881 [37532] [21912] [warning] [default] - Unable to assign [undefined] to QString 2025-04-21 17:19:41.881 [37532] [21912] [warning] [default] - TypeError: Value is null and could not be converted to an object
The issue seems to be that the created moc does not contain items enabled with `__has_include`.
- moc_testNG.cpp
/**************************************************************************** ** Meta object code from reading C++ file 'testNG.h' ** ** Created by: The Qt Meta Object Compiler version 68 (Qt 6.8.3) ** ** WARNING! All changes made in this file will be lost! *****************************************************************************/ #include "../../../../../../cannot-connect-to-slot/main/testNG.h" #include <QtCore/qmetatype.h> #include <QtCore/qtmochelpers.h> #include <memory> #include <QtCore/qxptype_traits.h> #if !defined(Q_MOC_OUTPUT_REVISION) #error "The header file 'testNG.h' doesn't include <QObject>." #elif Q_MOC_OUTPUT_REVISION != 68 #error "This file was generated using the moc from 6.8.3. It" #error "cannot be used with the include files from this version of Qt." #error "(The moc has changed too much.)" #endif #ifndef Q_CONSTINIT #define Q_CONSTINIT #endif QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED QT_WARNING_DISABLE_GCC("-Wuseless-cast") namespace { struct qt_meta_tag_ZN6TestNGE_t {}; } // unnamed namespace #ifdef QT_MOC_HAS_STRINGDATA static constexpr auto qt_meta_stringdata_ZN6TestNGE = QtMocHelpers::stringData( "TestNG" ); #else // !QT_MOC_HAS_STRINGDATA #error "qtmochelpers.h not found or too old." #endif // !QT_MOC_HAS_STRINGDATA Q_CONSTINIT static const uint qt_meta_data_ZN6TestNGE[] = { // content: 12, // revision 0, // classname 0, 0, // classinfo 0, 0, // methods 0, 0, // properties 0, 0, // enums/sets 0, 0, // constructors 0, // flags 0, // signalCount 0 // eod }; Q_CONSTINIT const QMetaObject TestNG::staticMetaObject = { { QMetaObject::SuperData::link<QObject::staticMetaObject>(), qt_meta_stringdata_ZN6TestNGE.offsetsAndSizes, qt_meta_data_ZN6TestNGE, qt_static_metacall, nullptr, qt_incomplete_metaTypeArray<qt_meta_tag_ZN6TestNGE_t, // Q_OBJECT / Q_GADGET QtPrivate::TypeAndForceComplete<TestNG, std::true_type> >, nullptr } }; void TestNG::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) { auto *_t = static_cast<TestNG *>(_o); (void)_t; (void)_c; (void)_id; (void)_a; } const QMetaObject *TestNG::metaObject() const { return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject; } void *TestNG::qt_metacast(const char *_clname) { if (!_clname) return nullptr; if (!strcmp(_clname, qt_meta_stringdata_ZN6TestNGE.stringdata0)) return static_cast<void*>(this); return QObject::qt_metacast(_clname); } int TestNG::qt_metacall(QMetaObject::Call _c, int _id, void **_a) { _id = QObject::qt_metacall(_c, _id, _a); return _id; } QT_WARNING_POP
Attachments
Gerrit Reviews
For Gerrit Dashboard: QTBUG-136097 | ||||||
---|---|---|---|---|---|---|
# | Subject | Branch | Project | Status | CR | V |
642931,3 | moc: support __has_include | dev | qt/qtbase | Status: NEW | -1 | 0 |