Unsolved It's possible to call c++ function from qml and update a ListModel?
-
I'm trying to update my ListModel but it is impossible.
If I set on my main.cpp
QStringList dataList; dataList.append("Item 222"); QQmlContext *ctxt = engine.rootContext(); ctxt->setContextProperty("myModel", QVariant::fromValue(dataList));
It's working.
But if a do the same on a excel.h doesn't work
QStringList dataList; dataList.append("Item 222"); QQmlApplicationEngine engine; QQmlContext *classContext = engine.rootContext(); classContext->setContextProperty("myModel", QVariant::fromValue(dataList));
It is not updating my combobox.
I need to open a excel and set combobox items but I can't.
Thanks and sorry for my bad english
-
This is described in depth in the documentation: link
Quoting:
Note: There is no way for the view to know that the contents of a QStringList have changed. If the QStringList changes, it will be necessary to reset the model by calling QQmlContext::setContextProperty() again.
-
Hm actually you are calling setContextProperty() again, so it should work. Are you sure you are updating correct model ("myModel" - is it correct)?
-
@sierdzio Yep because if I do on Main.cpp it's working. But when I call from qml to this function on excel.h doesn't work.
No errors, and no info on debugger.
Also I've got a
qmlRegisterType<Excel>("com.myself", 1, 0, "Excel");
line on main.cpp to call those functions on excel.h
-
Have thought about your list gets out of scope?
Cant see full sources, so cant say 100% sure, but it looks like it is -
I feel the delay in answering...
I can't paste my code here... I have this error message when I post it: Post content was flagged as spam by Akismet.com
Edit:
I suppose that I need "refresh" main.qml or reload it.
Here is my main.cpp
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QtQml> #include "Excel.h" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); qmlRegisterType<Excel>("com.myself", 1, 0, "Excel"); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); QStringList dataList; dataList.append("wololo"); engine.rootContext()->setContextProperty( "cppModel", QVariant::fromValue(dataList) ); return app.exec(); }
Class of excel file. I'm loading xlsxdocument plugin.
Excel.h#ifndef EXCEL_H #define EXCEL_H #include <QObject> #include "xlsx/xlsxdocument.h" #include "xlsx/xlsxabstractsheet.h" class Excel : public QObject { Q_OBJECT public: Q_INVOKABLE getExcel(QString path); signals: public slots: }; #endif // EXCEL_H
Here is my function that I'm trying to update my combobox model.
Excel.cpp#include "Excel.h" #include <QDebug> #include <QQmlApplicationEngine> #include <QtQml> Excel::getExcel(QString path) { path.remove(0,8); qDebug() << path; QXlsx::Document xlsx(path); xlsx.selectSheet("MOULD DIMENSIONS"); //etc.. QQmlApplicationEngine engine; QStringList dataList; dataList.append("Item 2"); engine.rootContext()->setContextProperty( "cppModel", QVariant::fromValue(dataList) ); }
And here is my main qml.
main.qmlimport QtQuick 2.5 import QtQuick.Window 2.2 import QtQuick.Controls 1.4 import QtQuick.Dialogs 1.2 import com.myself 1.0 Window { visible: true Excel { id: excel } Button { id: btnOpen width: 125 text: qsTr("Open Excel") clip: false } ComboBox { id: combo model: cppModel } FileDialog { id: fileDialog title: "Please choose a file" folder: shortcuts.home onAccepted: { excel.getExcel(fileDialog.fileUrls.toString()); } } Connections { target: btnOpen onClicked: fileDialog.visible = true } }
When I run, the combobox has only 1 item. 'wololo' item.
And when I open a Excel file, I need to change the combobox items. In this example I need to add 'Item 2' item to combobox.But is not working.
-
The 'engine' you create in getExcel() is not the same object as the one you create in main.cpp... so you are setting the root property on a different engine than the one you use to display QML :-)
To fix this, just pass the engine (or the root context) pointer to your Excel class and use it in getExcel().
-
Another option is to use parent-child hierarchy instead of root properties.
So, in QML:
Excel { ComboBox { id: combo objectName: "combo" } }
And then set model from CPP:
// Pseudocode, written from memory. Please check the docs to be sure: QObject *combo = findChildren<QQuickItem*>("combo"); // combo is a child of Excel in QML! if (combo) { combo->setProperty("model", QVariant::fromValue(dataList) ); }
Not sure which one you'll find more aesthetic (also not sure if the second option would work at all ;-) ).
-
@sierdzio said:
The 'engine' you create in getExcel() is not the same object as the one you create in main.cpp... so you are setting the root property on a different engine than the one you use to display QML :-)
To fix this, just pass the engine (or the root context) pointer to your Excel class and use it in getExcel().
Oh!! It's true... I supose that If I create a engine on main, I can use It on another cpp or h class...
But now I have a another question... How I can pass engine, or root from main to qml and them from qml to function?
Anyway, I will try the parent-child
-
@sdsoldi said:
How I can pass engine, or root from main to qml and them from qml to function?
You can create a singleton class in C++, pass the engine pointer to it in main.cpp, and then simply access it in your Excel class. This is probably the simplest solution, although singletons do have their drawbacks.
Or add the engine as a context property to QML, then assign it to Excel object... although that seems awkward.
-
or use
QQmlEngine *qmlEngine(const QObject *object) -
@vladstelmahovsky Can you explain it please?
-
It is a static method of the engine. SO you can probably use it like this (in Excel class):
QQmlEngine *engine = qmlEngine(this); // because "this" is an item you have added to QML QStringList dataList; dataList.append("Item 2"); engine.rootContext()->setContextProperty( "cppModel", QVariant::fromValue(dataList) );
-
@sierdzio @vladstelmahovsky
Oh my god! It's as simple as that...Thank you very much!
-
yep, but dont forget to check for null