3

My Projects contains 6 qml Files: The main.qml opens a new ApplicationWindow and declares the toolbar. It also initalizes StackView with the initalItem homescreen.qml. On the Home Screen I have different buttons which open different qml Files, via stack.push("URL"). Besides the main.qml all Files start with Item{}. I've been able to connect signals from the main.qml and the home.qml. But I've been unable to access Objects that are deeper in the stack. I don't know if I hvae to change my .cpp code to access the other objects, or if I should change the Initalization of StackView, so that all Files are loaded and accessible at the beginning. Here is the code, broke down to the very basics:

  • main.qml

    ApplicationWindow {
          Rectangle{
                    id: homeButton
                    objectName: "homeButton"
                    signal qmlSignal(string msg)
                    MouseArea {
                         onClicked:  {stack.push({item:"qrc:/home.qml}); homeButton.qmlSignal("Hello")}
                    }
          }
          StackView{
               initalItem: "qrc:/home.qml"
          }
    

    }

  • secondframe.qml // A randomw qml File that comes after the Home Screen

    Item {
          Rectangle{
                    id: test
                    objectName: "test"
                    signal qmlSignal(string msg)
                    MouseArea {
                         onClicked:  {stack.push({item:"qrc:/thirdframe.qml}); test.qmlSignal("Hello")}
                    }
          }
    }
    
  • main.cpp

    QApplication app (argc, argv);
    QQmlEngine enigne;
    QQmlComponent component(&engine, QUrl(QStringLiteral("qrl:/main.qml")));
    QObject *object = componet.create();
    QQmlComponent newcomponent(&engine, QUrl(QStringLiteral("qrl:/secondframe.qml")));
    QObject *newobject = newcomponet.create();
    
    MyClass myClass
    QObject *home = object->findChild<QObject*>("homeButton");    // I'm able to connect to every Object in the main.qml or home.qml
    QObject::connect(home,SIGNAL(qmlSignal(Qstring)), &myClass, SLOT(cppSlot(QString)));
    QObject *test = newobject->findChild<QObject*>("test");       // Can't connect to the Objects in secondframe.qml
    QObject::connect(test,SIGNAL(qmlSignal(Qstring)), &myClass, SLOT(cppSlot(QString)));
    
MilloMille
  • 35
  • 1
  • 8
  • how does secondframe.qml has access to the stack object? I have an app with a Stackview which n pages. I need to navigate from one page to another page. How do I do that? – jxgn Nov 08 '17 at 12:35

2 Answers2

3

A way better approach than to reach into the QML tree and pull out objects that might or might not be there is to provide C++ based API to QML.

  1. Create a QObject based class that has the methods QML needs to be able to call as slots or Q_INVOKABLE

    class MyAPI : public QObject
    {
        Q_OBJECT
    public slots:
        void cppSlot(const QString &text);
    };
    
  2. Create an instance of that and expose it to QML

    MyAPI myApi;
    QQmlEngine engine;
    engine.rootContext()->setContextProperty("_cppApi", &myApi);
    
  3. Use in QML as if "_cppApi" is an object id

    MouseArea {
         onClicked:  {stack.push({item:"qrc:/thirdframe.qml}); _cppApi.cppSlot("Hello")}
    }
    
Kevin Krammer
  • 5,159
  • 2
  • 9
  • 22
  • Thanks a lot!!! You are a programming heavyweight champion and a very beautiful person. I am so happy this finely works. thanks for taking the time to look into my problem – MilloMille Jan 25 '17 at 11:11
  • 4
    To show you that this is no secret only known to heavyweight programming champions I present to you the allmighty Qt Documentation: http://doc.qt.io/qt-5/qtqml-cppintegration-interactqmlfromcpp.html – Mailerdaimon Jan 25 '17 at 11:57
  • There is some work ongoing to make this particular documentation more accessible/discoverable, but I think it would still be good to hear what users think; how could the documentation be improved, were they able to find it, etc. Suggestions are always welcome: bugreports.qt.io – Mitch Jan 25 '17 at 12:14
  • @Mailerdaimon That is actually the page I used and it didn't help me for my particular problem. As I described QObject::connect didn't enable me access files that are not loaded upon initiation. With Kevins solution of passing the class to QML i was able to interact with every Object I wanted. Maybe I made a mistake when using the ::connect method, but anyway the solution of Kevin isn't included in the help page – MilloMille Jan 25 '17 at 12:50
  • 3
    OP: Probably better to have a look to [this page](http://doc.qt.io/qt-5/qtqml-cppintegration-exposecppattributes.html). @Mitch the documentation keeps improving A LOT between each release. What it is missing, sometimes, is some sort of "best practice" or "general advices". Something similar to [this](http://doc.qt.io/qt-5/threads-technologies.html#example-use-cases) but applied to quick topics (e.g. context properties vs. registering types) can be very useful to new comers. Just my .02 cents. :) – BaCaRoZzo Jan 25 '17 at 16:38
  • @Mailerdaimon you have a long way of raising the bar for "sophisticated". This solution is actually not only entirely trivial but also sub-par, because it would involve an expressive lookup, for something like an "API" that is a single global object, a singleton would be a much more efficient and elegant solution. – dtech Jan 25 '17 at 17:03
  • @Mailerdaimon I hope you don't take it personally, no one is born learned, it is just a good idea to reserve judgements for what's sophisticated for until you are. The documentation isn't stellar either, for example the relevant paragraph is called "Exposing properties" but what it really should be named is "Exposing objects as properties" because most of the time it will be used for exactly this, so it is a little misleading in the context that properties tend to usually be simple values rather than complex objects with properties, functions and such. But still, it is very basic stuff. – dtech Jan 26 '17 at 14:56
  • @Mailerdaimon - in that case it is just a poor choice of word, "sophisticated" means "involving high degree of complexity". It could be more "complete", or "full-proof" or "newb friendly" or "specific" but certainly not "sophisticated" ;) Also, I wasn't under the impression that SO is mostly copy and paste answers, but maybe we are looking at a different subset of the site. – dtech Jan 26 '17 at 16:00
-1

After pushing qmls on the stack, objects will be accessible. So when you emit some signal, when object will be on the stack, solution can look like this:

MyClass myClass
QObject *home = object->findChild<QObject*>("homeButton");    // I'm able to connect to every Object in the main.qml or home.qml
QObject::connect(home,SIGNAL(qmlSignal(Qstring)), &myClass, SLOT(cppSlot(QString)));

connect( myClass, MyClass::emitWhenQMLIsAlreadyOnTheStack, this, [this](){
    QObject *test = newobject->findChild<QObject*>("test");       // Now you should be able to connect
    QObject::connect(test,SIGNAL(qmlSignal(Qstring)), &myClass, SLOT(cppSlot(QString));
});
wair92
  • 446
  • 11
  • 24