{"id":309,"date":"2010-12-29T17:29:19","date_gmt":"2010-12-30T00:29:19","guid":{"rendered":"http:\/\/www.lothlorien.com\/kf6gpe\/?p=309"},"modified":"2011-02-21T15:48:05","modified_gmt":"2011-02-21T22:48:05","slug":"calling-a-qml-item-method-from-c","status":"publish","type":"post","link":"https:\/\/www.lothlorien.com\/kf6gpe\/calling-a-qml-item-method-from-c\/","title":{"rendered":"Calling a QML item method from C++"},"content":{"rendered":"<p>This is another one of those &#8220;it&#8217;s all in the documentation&#8221;, but for whatever reason, I had a heck of a time finding the info when I needed it. (The Qt documentation is generally great &#8212; I&#8217;m not beefing about that, but rather my personal inability to remember bits of it and not have enough remembered that I can search on things efficiently).<\/p>\n<p>There&#8217;s times where you want to have something in C++ call a method defined by a QML item. In my case, I had a <code>ListView<\/code> that I wanted to manually reposition when its model (a C++ object derived from <code>QStandardItemModel<\/code>) changed under certain circumstances. I began with a <code>ListView<\/code> that looked something like this:<\/p>\n<pre>\r\n    ListView {\r\n        id: events\r\n        objectName: \"events\"\r\n\r\n        property bool moved: false\r\n\r\n        model: appmodel\r\n        delegate: MyItemDelegate {}\r\n        Component.onCompleted: positionViewAtIndex(count - 1, ListView.End)\r\n        onMovementStarted: moved = true\r\n        function positionListAtEnd() {\r\n            if (!moved) events.positionViewAtIndex(events.count - 1, ListView.End)\r\n        }\r\n    }\r\n<\/pre>\n<p>Here, I&#8217;m going to use the <code>moved<\/code> property to track whether the user&#8217;s interacted with the list view at all; if she&#8217;s moved the list view, I don&#8217;t want to start yanking it around when the model updates, but if it&#8217;s just sat unused and the model updates, I want the list to always show the last item in the model. When the list view first loads, I do that manually using the <code>onCompleted<\/code> signal handler; I also want to do it when the model changes, by having the code that updates the model invoke the <code>ListView<\/code>&#8216;s <code>positionListAtEnd<\/code> method.<\/p>\n<p>The trick is actually getting a reference to the <code>QObject<\/code> that corresponds to my <code>ListView<\/code>. In QML, items are referenced by their <code>id<\/code> property; in Qt&#8217;s meta-object system, they&#8217;re referenced by object name&#8212;denoted by the <code>objectName<\/code> property, a string bearing the object&#8217;s name. <\/p>\n<p><em>Don&#8217;t confuse the two!<\/em> You can&#8217;t link QML things using object names, and, as near as I can tell, the Qt meta-object system&#8217;s C++ implementation doesn&#8217;t care one whit about QML ids. <\/p>\n<p>So I give my <code>ListView<\/code> an <code>objectName<\/code> property, which for sanity&#8217;s sake is the same as the <code>id<\/code> I&#8217;ve assigned: <code>\"events\"<\/code>. It&#8217;s a string, not a name, so those quotes in the QML are important. Once I&#8217;ve done that, I can find this object by name in my QML hierarchy using the following bit of C++:<\/p>\n<pre>\r\n    QObject *object = mView.rootObject();\r\n    if (!object) return;\r\n\r\n    QObject* listView = object->findChild&lt;QObject *&gt;(\"events\");\r\n    QVariant returnedValue;\r\n    QMetaObject::invokeMethod(listView, \"positionListAtEnd\",\r\n            Q_RETURN_ARG(QVariant, returnedValue));\r\n<\/pre>\n<p>The <code>mView<\/code> field is just the <code>QDeclarativeView<\/code> that renders my QML; you can see how I originally linked my C++ and QML in my previous post, <a href=\"http:\/\/www.lothlorien.com\/kf6gpe\/?p=160\">Adding C++ Objects to your QML<\/a>. It has a <em>root object<\/em>, a <code>QObject<\/code> descendant (really, a <code>QGraphicsObject<\/code> that corresponds to the top level of the QML object hierarchy being displayed). To invoke my QML method, I use Qt&#8217;s meta-object protocol to first find the child named <code>\"events\"<\/code> and then invoke its <code>positionListAtEnd<\/code> method, discarding the value it returns. <\/p>\n<p>There&#8217;s no magic here&#8212;as long as you remember that QML items can have an <code>objectName<\/code> property, and that property is used internally by Qt&#8217;s object hierarchy as the object&#8217;s name.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is another one of those &#8220;it&#8217;s all in the documentation&#8221;, but for whatever reason, I had a heck of a time finding the info when I needed it. (The Qt documentation is generally great &#8212; I&#8217;m not beefing about that, but rather my personal inability to remember bits of it and not have enough &hellip; <a href=\"https:\/\/www.lothlorien.com\/kf6gpe\/calling-a-qml-item-method-from-c\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Calling a QML item method from C++<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[10,9],"tags":[],"class_list":["post-309","post","type-post","status-publish","format-standard","hentry","category-mobile","category-programming"],"_links":{"self":[{"href":"https:\/\/www.lothlorien.com\/kf6gpe\/wp-json\/wp\/v2\/posts\/309","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lothlorien.com\/kf6gpe\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.lothlorien.com\/kf6gpe\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.lothlorien.com\/kf6gpe\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lothlorien.com\/kf6gpe\/wp-json\/wp\/v2\/comments?post=309"}],"version-history":[{"count":7,"href":"https:\/\/www.lothlorien.com\/kf6gpe\/wp-json\/wp\/v2\/posts\/309\/revisions"}],"predecessor-version":[{"id":323,"href":"https:\/\/www.lothlorien.com\/kf6gpe\/wp-json\/wp\/v2\/posts\/309\/revisions\/323"}],"wp:attachment":[{"href":"https:\/\/www.lothlorien.com\/kf6gpe\/wp-json\/wp\/v2\/media?parent=309"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.lothlorien.com\/kf6gpe\/wp-json\/wp\/v2\/categories?post=309"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lothlorien.com\/kf6gpe\/wp-json\/wp\/v2\/tags?post=309"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}