Hi Rob, Looks like a you did a pretty thorough analysis. If I understand you correctly, I can't really reproduce the problem with a test case I made.
The test case I made consists of CustomButton.h, CustomButton.cpp, CustomButton.qml, main.qml and main.cpp as follows: CustomButton.h: #pragma once #include <QQuickItem> class CustomButton : public QQuickItem { Q_OBJECT public: CustomButton(QQuickItem *parent = nullptr); }; CustomButton.cpp: #include "CustomButton.h" CustomButton::CustomButton(QQuickItem *parent) : QQuickItem(parent) { } CustomButton.qml: import QtQuick 2.0 import com.glob.myApp 1.0 CustomButton { signal clicked() property string text; function foo(arg) { console.info("foo called from " + arg); } Rectangle { anchors.fill: parent color: "red" } MouseArea { anchors.fill: parent onClicked: parent.clicked() } Text { anchors.centerIn: parent text: parent.text } } main.qml: import QtQuick 2.0 import QtQuick.Window 2.2 Window { visible: true CustomButton { width: 100 height: 30 text: "Click me" objectName: "button" onClicked: console.info("button clicked (from QML)"); Component.onCompleted: { console.log("component completed"); foo("QML"); } } } main.cpp: #include "CustomButton.h" #include <QDebug> #include <QGuiApplication> #include <QMetaObject> #include <QQmlApplicationEngine> #include <QVariant> class MyClass : public QObject { Q_OBJECT public slots: void cppSlot() { qDebug() << "button clicked (from C++)"; } }; int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); qmlRegisterType<CustomButton>("com.glob.myApp", 1, 0, "CustomButton"); QQmlApplicationEngine engine("main.qml"); QObject *button = engine.rootObjects().first()->findChild<QObject *>("button"); // Call foo() on button QVariant returnedValue; QMetaObject::invokeMethod(button, "foo", Q_RETURN_ARG(QVariant, returnedValue), Q_ARG(QVariant, "C++")); // Listen to the clicked signal of button MyClass myClass; QObject::connect(button, SIGNAL(clicked()), &myClass, SLOT(cppSlot())); return app.exec(); } #include "moc_main.cpp" Now, if I run this test case, I get the following (if I click the button once): [estan@pyret qmltest]$ ./qmltest qml: component completed qml: foo called from QML qml: foo called from C++ qml: button clicked (from QML) button clicked (from C++) [estan@pyret qmltest]$ It would help to see some of your code to see where things go wrong. Elvis 2016-08-31 8:08 GMT+02:00 Rob Allan <rob_al...@trimble.com>: > I have a custom QML type, CustomButton, defined in CustomButton.qml. > Initially this was a fairly simple type, with a 'clicked' signal, and a few > JavaScript functions that set up the button content. I was able to use this > custom button from other QML files, and from C++ code (using > QMetaObject::invokeMethod() to invoke its methods), and it all worked pretty > well. > > As this button became more complex, I realised that I really needed a C++ > wrapper class (or backing class?) to deal with some of the additional > complexity. I've added C++ wrapper classes to other QML types before, with > varying degrees of success, and I think I understand the basic steps > involved. I did the following: > > Created a minimal wrapper in CustomButton.h and CustomButton.cpp (I made > this as minimal as possible to begin with so as not to affect the existing > behavior - I thought!): > > #include <QQuickItem> > > class CustomButton : public QQuickItem > { > Q_OBJECT > > public: > CustomButton(); > }; > > Added the necessary qmlRegisterType() call to my application startup code: > > qmlRegisterType<CustomButton>("com.glob.myApp", 1, 0, "CustomButton"); > > Added an import statement to my CustomButton.qml file: > > import com.glob.myApp 1.0 > > Changed the root item in CustomButton.qml from 'Item' to 'CustomButton'. > > So far all appeared to be OK - the project compiled, and CustomButton.qml > appeared to be error-free in the QML editor. But then things started going > downhill. > > I noticed that, in another QML file that used CustomButton, it could no > longer 'see' the signals on my type - a reference to 'onClicked' was > red-underlined, and hovering over it showed 'Invalid property name'. At > runtime, it failed to create the referencing QML object due to this error. > It looks as if the introduction of the C++ wrapper class has 'hidden' the > signals defined in the original CustomButton.qml file. > > I found I could get past this error by deleting the signal definitions from > CustomButton.qml, and instead adding them to CustomButton.h: > > signals: > void clicked(const QString text, int eventCode); > etc... > > That allowed it to build and run. I'm not sure whether this was correct and > the signals would now have worked, because I then struck another problem - > my existing C++ code could no longer invoke the JavaScript functions defined > in CustomButton.qml. For example, when I tried to invoke a method > 'setContent' (which previously worked just fine) I now got this runtime > error: > > QMetaObject::invokeMethod: No such method > CustomButton::setContent(QVariant,QVariant) > > Again, it appears that adding a C++ wrapper class has 'hidden' the function > definitions in the QML file, that were previously available to the rest of > the system. > > OK, I thought, maybe I have to define these functions on the C++ class in > some way. I tried declaring an INVOKABLE function in the .h file that > matched my JavaScript function, and that failed with a link error - the > compiler wanted me to define an implementation for this function in my CPP > file - but I don't want to implement it in my CPP file, as the > implementation exists in the QML file! Just to see where it got me, I tried > adding an implementation to the CPP file, and inside this function, > attempted to "invoke" the JavaScript function. That failed, presumably > because I had now introduced a kind of circularity and was probably > attempting to invoke the same handler that I was already in! > > I also tried declaring these functions as 'slots' on the C++ class, but > fared no better - the compiler still wanted a CPP implementation, and I > wasn't sure if I was really meant to add one, and if I did, how I would then > invoke the JavaScript function from it. > > In short - adding a C++ wrapper class (with almost nothing in it) has broken > a previously functional QML type implementation, by apparently 'hiding' > signals and functions that exist in the QML. > > Can anyone advise what I'm doing wrong here? Or suggest some relevant > documentation that might give me the answers I need? > > Thanks, > Rob > > > _______________________________________________ > Interest mailing list > Interest@qt-project.org > http://lists.qt-project.org/mailman/listinfo/interest > _______________________________________________ Interest mailing list Interest@qt-project.org http://lists.qt-project.org/mailman/listinfo/interest