[SOLVED] Qt5 Android: QML & C++ communication



  • Hi,
    I'M trying to adjust my existing QML/C++ app for Android and have following problem:

    this is my exisitng Qt4 code which works on win32 & linux x86/x86_64:
    @
    QObject * btn = this->rootObject()->findChild<QObject*>("login_btn");
    if(btn != NULL)QObject::connect(btn, SIGNAL(clicked(const QString &, const QString &)),this->crm, SLOT(Login(const QString &, const QString&)));
    else qWarning() << "Can't find login button object on splash screen";
    @

    "this" is subclass of QDeclarativeView. I've changed it to QQuickView because of Qt5. So, on Android with Qt5 this code doesn't work and always fails to qWarning.... I have checked rootObject()->children() list and all objects have empty objectName().

    Can someone confirm this? Is there new way to find objects in qml in Qt5?



  • OK, with Qt 5.1.2 on desktop environment same problem... objectNames are empty...



  • Hi,

    Strange... Do you have the same objects count in you view as in your QML ? Are the names really empty or just different ?

    Although I'm sure you know directly accessing QtQuick components is clearly not the "recommanded way" of using QtQuick, I doubt they would have deliberatly broken the findChild method.


  • Moderators

    Why do you think it's not recommended? It's one of the beauties of meta object system... For me it still works, although the newest Qt I've tried is 5.1.0.



  • Well because that kinda break the C++/QML separation, and is do-able by keeping that separation. Actually I didn't noticed there was no QML modification at all from the C++ side , so that's not a big deal.

    And anyway if sierdzio says it's alright, I'm not gonna contradict him ;).



  • [quote author="Adrien Leravat" date="1378886364"]Hi,

    Strange... Do you have the same objects count in you view as in your QML ? Are the names really empty or just different ?

    Although I'm sure you know directly accessing QtQuick components is clearly not the "recommanded way" of using QtQuick, I doubt they would have deliberatly broken the findChild method.

    [/quote]

    They are emtpy, all of them... but in qml file id is set for most of them... and yes, item count is the same....
    directly accessing QtQuick components is clearly recommendet way since was introduced in Qt4 for QML/C++ communication.

    [quote author="sierdzio" date="1378886962"]Why do you think it's not recommended? It's one of the beauties of meta object system... For me it still works, although the newest Qt I've tried is 5.1.0.[/quote]

    Have tried it with Qt 5.0.1 SDK for linux, and got same thing... objectNames are empty.... Maybe I'm missing something in my code....

    qml file:
    @
    import QtQuick 2.0

    Rectangle
    {
    id: gui_main

    Item
    {
        id: item_list
        anchors.top: item_search.bottom
        anchors.left: parent.left
        anchors.bottom: parent.bottom
        width: parent.width*0.9
    
        ListView
        {
            id: list_contacts
            anchors.fill: item_list
            model: ContactsModel
            delegate: contactDelegate
    
            highlight: highlight
            highlightFollowsCurrentItem: false
            focus: true
    
            Component.onCompleted:
            {
                positionViewAtIndex(1, ListView.Beginning)
            }
        }
    }
    
    Item
    {
        id: item_search
        x: 0
        y: 0
        width: parent.width
        height: gui_main.width>gui_main.height?parent.height*0.05:parent.height*0.03
        signal searchFor(string str)
        Rectangle
        {
            anchors.fill: item_search
            color: "darkblue"
            Rectangle
            {
                anchors.fill: parent
                anchors.margins: 4
    
                color: "white"
                radius: 2
    
                TextInput
                {
                    id: item_search_text_input
                    anchors.fill: parent
                    anchors.leftMargin: 5
                    anchors.rightMargin: 5
    
                    font.pixelSize: parent.height-8
                    text: qsTr("")
                     Keys.onReturnPressed:
                    {
                        item_list.focus = true;
                        Qt.inputMethod.hide();
                         item_search.searchFor(text);
                    }
                }
            }
        }
    }
    

    ...
    @

    QQuickView subclass:
    @
    CRMGUI::CRMGUI(QWindow *parent):
    QQuickView(parent),
    m_load_counter(0),
    crm(new CRMWebServices(this)),
    m_model(new CRMContactsListModel(this)),
    m_sort_model(new CRMContactsSortModel(this))
    {
    connect(this->engine(), &QQmlEngine::quit, this, &CRMGUI::close);
    this->setResizeMode(QQuickView::SizeRootObjectToView);

    this->m_sort_model->setSourceModel(this->m_model);
    
    QQmlContext * context = this->rootContext();
    context->setContextProperty("scale",1 /* Calculate scale value for each display size */);
    context->setContextProperty("viewerWidget",this);
    context->setContextProperty("ContactsModel", this->m_sort_model);
    
    connect(this, &CRMGUI::statusChanged, this, &CRMGUI::viewStatusChanged);
    

    }

    void CRMGUI::setMainQmlFile(const QString &file)
    {
    this->m_main_qml = QString::fromLatin1("%1/../%2").arg(QCoreApplication::applicationDirPath(), file);
    if(!QFileInfo(this->m_main_qml).exists())
    {
    this->m_main_qml = QString::fromLatin1("%1/%2").arg(QCoreApplication::applicationDirPath(), file);
    if(!QFileInfo(this->m_main_qml).exists())this->m_main_qml = file;
    }

    #ifdef Q_OS_ANDROID
    setSource(QUrl(QLatin1String("assets:/")+this->m_main_qml));
    #else
    setSource(QUrl::fromLocalFile(this->m_main_qml));
    #endif
    }

    void listObjs(QObject * obj)
    {
    QObjectList list = obj->children();
    foreach(QObject * obj, list)
    {
    qDebug() << obj->objectName();
    listObjs(obj);
    }
    }

    void CRMGUI::viewStatusChanged(QQuickView::Status status)
    {
    if(status == QQuickView::Ready)
    {

        QObjectList list = this->rootObject()->children();
        foreach(QObject * obj, list)
        {
            qDebug() << obj->objectName();
            listObjs(obj);
        }
    
        QObject * search_item = this->rootObject()->findChild<QObject *>("item_search");
        if(search_item != 0)
        {
            connect(search_item, SIGNAL(searchFor(QString&)), this, SLOT(Search(QString&)));
        }else qDebug() << "Object not found"; 
    }
    

    }

    @

    main loop:
    @
    int main(int argc, char *argv[])
    {
    QGuiApplication app(argc, argv);

    CRMGUI viewer;
    viewer.setMainQmlFile(QStringLiteral("qml/CRM/main.qml"));
    viewer.show();

    return app.exec();
    

    }
    @

    item_search item is exist and id is set in qml... I'm searching for it after QQuickView becomes Ready... no idea what's wrong...


  • Moderators

    Ah, ok it's clear now. QML's id is not the same as objectName. Ids are internal QML stuff, completely invisible in C++ (and outside of QML scope, even to other Components). If you want to use meta object system, you have to specify object name by hand:
    @
    Item {
    id: myItem
    objectName: "myItem"
    }
    @



  • **** i knew I have missed something.... Thanks sierdzio!


  • Moderators

    No, it's stored internally in private parts of QQuickItem. There is no way to get it in C++ without changing Qt library source code.

    This has been raised on Qt bugtracker and mailing lists, but IIRC devs are reluctant to change it, due to some technicalities I don't remember right now.

    On the plus side, this lowers meta object overhead: only those you explicitly name using "objectName" are visible.



  • Thank you for clarification!


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.