eudoxos
eudoxos

Reputation: 19075

Access nested object in QML slot by id (called from c++)

I used to have this arrangement of a window with one text field in it, updated with data emitted from c++ :

Window{
   id: root
   function qmlSlot(a){
      _textField1.text=a;
   }
   TextField{
      id: _textField1
   }
}

The binding is like this:

QQuickWindow *window=qobject_cast<QQuickWindow*>(topLevel);
QObject::connect(src,SIGNAL(someSignal(QVariant)),window,SLOT(qmlSlot(QVariant)));

Now I added more things (tabs) to the main window and things don't work straightforwardly anymore.

A: When I leave qmlSlot in the Window scope, it does not see _textField1:

Window{
   id: root
   function qmlSlot(a){
      _textField1.text=a;
   }
   TabView{
      Tab{
         TextField{
            id: _textField1
         }
      }
   }
}

which gives me:

qrc:/main.qml:32: ReferenceError: _textField1 is not defined

B: When I move the slot itself to the scope of _textField1, I don't know how to bind to it from c++:

Window{
   id: root
   TabView{
      Tab{
         function qmlSlot(a){
            _textField1.text=a;
         }
         TextField{
            id: _textField1
         }
      }
   }
}

resulting in:

QObject::connect: No such slot QQuickWindowQmlImpl_QML_21::qmlSlot(QVariant)

How can I have qmlSlot called from c++ while accessing nested items (_textField in this case)? Is it possible to make it such that I don't have to change the binding code when I decide to change the window layout?

Upvotes: 2

Views: 1486

Answers (2)

GrecKo
GrecKo

Reputation: 7150

Your problem is that Tab is in fact a Loader, so it means that your TextField is created on demand and in another context. When your Tab isn't active there is no TextField to access.

You could access your textfield with tab.item, but it would only work when the tab is loaded.

You have a deeper problem though, accessing QML objects from c++ is bad practice as that means that your business layer has to be aware of your UI layer. That's not good if you want to refactor your UI. What you should do instead is pull data from c++ in your QML. More explanation here : Interacting with QML from C++.

In your case, I would create a QObject subclass with a property or a signal (is it a state of your object or an event?).

Then use setContextProperty to make one of your object instance available to the QML engine.

And in your QML you'd just do (if it's a property):

Window{
   id: root
   TabView{
       Tab{
           TextField{
               text: myCppObject.textProperty
            }
        }
    }
}

Upvotes: 2

Troubadour
Troubadour

Reputation: 13421

I've never used QML before but the docs suggest that you need to assign a value to each object's id property so that you can refer to it. I think the following should work (but have not tested it).

Window{
   id: root
   function qmlSlot(a){
      mytabview.mytab._textField1.text=a;
   }
   TabView{
      id: mytabview
      Tab{
         id: mytab
         TextField{
            id: _textField1
         }
      }
   }
}

Upvotes: -1

Related Questions