2016-08-31 19:24 GMT+02:00 Elvis Stansvik <elvst...@gmail.com>: > 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:
Attaching these in qmltest.tar.gz. Elvis > > 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 >>
qmltest.tar.gz
Description: GNU Zip compressed data
_______________________________________________ Interest mailing list Interest@qt-project.org http://lists.qt-project.org/mailman/listinfo/interest