QStringList in QML?
-
wrote on 15 Jul 2019, 12:59 last edited by
Yes - moduleFinder.h:
#ifndef MODULEFINDER_H #define MODULEFINDER_H #include <QObject> #include <QStringListModel> class moduleFinder : public QObject { Q_OBJECT Q_PROPERTY(QStringList moduleIo MEMBER m_moduleIo NOTIFY moduleIoChanged) public: explicit moduleFinder( QObject *parent = nullptr ); QString fileName = "list.txt"; QString module; QStringList ioList; QStringList moduleIo; Q_INVOKABLE void loadModules(); QStringList getIo(QString); int index = 0; int newIndex = 0; public slots: Q_INVOKABLE void setModule( const QString m_module ); signals: void moduleIoChanged(const QStringList &newModuleIoList); private: }; #endif // MODULEFINDER_H
moduleFinder.cpp:
#include "modulefinder.h" #include <QFile> #include <QDebug> moduleFinder::moduleFinder(QObject *parent) : QObject(parent) {} void moduleFinder::setModule(QString m_module) { module = m_module; getIo(module); } void moduleFinder::loadModules(){ QFile moduleFile(fileName); if (!moduleFile.exists()) { qWarning() << "file doesn't exist!";} else if (!moduleFile.open(QIODevice::ReadOnly | QIODevice::Text)) { qWarning() << "Not open"; } else { QTextStream textStream(&moduleFile); while (!textStream.atEnd()) ioList << textStream.readLine(); moduleFile.close(); } } QStringList moduleFinder::getIo(QString myModule) { //qDebug()<<myModule; int lines = ioList.length(); QString moduleId = myModule; for (int i=0;i<lines;i++) { //qDebug()<< "IO List" <<ioList.at(i); if (ioList.at(i).contains(moduleId)) { // if module is found in list index = i; // get index of position in list } } newIndex = index + 32; for (int y=index+1; y<newIndex+1; ++y) { // and copy relevant lines into new list moduleIo << ioList.at(y); // <-this is the QStringList I want to access } emit moduleIoChanged(m_moduleIo); //qDebug()<< moduleIo; }
loadModules() is run once from main.cpp when the program starts.
-
Yes - moduleFinder.h:
#ifndef MODULEFINDER_H #define MODULEFINDER_H #include <QObject> #include <QStringListModel> class moduleFinder : public QObject { Q_OBJECT Q_PROPERTY(QStringList moduleIo MEMBER m_moduleIo NOTIFY moduleIoChanged) public: explicit moduleFinder( QObject *parent = nullptr ); QString fileName = "list.txt"; QString module; QStringList ioList; QStringList moduleIo; Q_INVOKABLE void loadModules(); QStringList getIo(QString); int index = 0; int newIndex = 0; public slots: Q_INVOKABLE void setModule( const QString m_module ); signals: void moduleIoChanged(const QStringList &newModuleIoList); private: }; #endif // MODULEFINDER_H
moduleFinder.cpp:
#include "modulefinder.h" #include <QFile> #include <QDebug> moduleFinder::moduleFinder(QObject *parent) : QObject(parent) {} void moduleFinder::setModule(QString m_module) { module = m_module; getIo(module); } void moduleFinder::loadModules(){ QFile moduleFile(fileName); if (!moduleFile.exists()) { qWarning() << "file doesn't exist!";} else if (!moduleFile.open(QIODevice::ReadOnly | QIODevice::Text)) { qWarning() << "Not open"; } else { QTextStream textStream(&moduleFile); while (!textStream.atEnd()) ioList << textStream.readLine(); moduleFile.close(); } } QStringList moduleFinder::getIo(QString myModule) { //qDebug()<<myModule; int lines = ioList.length(); QString moduleId = myModule; for (int i=0;i<lines;i++) { //qDebug()<< "IO List" <<ioList.at(i); if (ioList.at(i).contains(moduleId)) { // if module is found in list index = i; // get index of position in list } } newIndex = index + 32; for (int y=index+1; y<newIndex+1; ++y) { // and copy relevant lines into new list moduleIo << ioList.at(y); // <-this is the QStringList I want to access } emit moduleIoChanged(m_moduleIo); //qDebug()<< moduleIo; }
loadModules() is run once from main.cpp when the program starts.
@MScottM
I'm surprised this actually compiles, as your class has no memberm_moduleIo
the member variable is calledmoduleIo
-
wrote on 15 Jul 2019, 16:51 last edited by
Oh, I put it under 'private':
private: QStringList m_moduleIo;
I had been trying a couple different things to get something to work - I copied and pasted the code above from between a change I had tried.
-
Oh, I put it under 'private':
private: QStringList m_moduleIo;
I had been trying a couple different things to get something to work - I copied and pasted the code above from between a change I had tried.
@MScottM
I have some difficulties to follow your problem.Does this simple example help you?
//main.cpp #include <QApplication> #include <QQmlApplicationEngine> #include "myclass.h" #include "QQmlContext" int main(int argc, char *argv[]) { QApplication app(argc, argv); QQmlApplicationEngine engine; myClass mClass; engine.rootContext()->setContextProperty("cppListModel", &mClass); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; return app.exec(); }
//main.qml import QtQuick 2.9 import QtQuick.Window 2.2 import QtQuick.Controls 2.5 Window { visible: true width: 640 height: 480 title: qsTr("Hello World") id:root ListView{ id: listView anchors.fill: parent model: cppListModel.myListModel delegate:Text { text: modelData color: index % 2 ? "red" : "blue" } } }
//myClass #ifndef MYCLASS_H #define MYCLASS_H #include <QObject> class myClass : public QObject { Q_OBJECT Q_PROPERTY(QStringList myListModel READ myListModel WRITE setMyListModel NOTIFY myListModelChanged) public: explicit myClass(QObject *parent = nullptr) :QObject(parent) { setMyListModel({"Item1", "Item2", "Item3", "Item4"}); } QStringList myListModel() const { return m_myListModel; } signals: void myListModelChanged(QStringList myListModel); public slots: void setMyListModel(QStringList myListModel) { if (m_myListModel == myListModel) return; m_myListModel = myListModel; emit myListModelChanged(m_myListModel); } private: QStringList m_myListModel; }; #endif // MYCLASS_H
-
wrote on 16 Jul 2019, 13:36 last edited by
Hi @J-Hilk,
Thank you for your example - I apologize for not being more clear in what I'm trying to do. I have a GUI that I want to display the inputs and outputs of the modules of a PLC, so that when a user clicks the module button, the main page updates with that modules' list of I/O.
An over-simplified example:
I can't get a ListView to work because it displays the whole list at a time, so I am trying to access a QStringList by index and put each indexes text in a corresponding label.
I hope that better explains the problem I'm having!
Best regards.
-
wrote on 16 Jul 2019, 20:52 last edited by
I've made some progress following a different track!
I was able to bring the QStringList into QML by using a function to create an array:
Button { id: clickme x: 170 y: 0 visible: true height: 100 width: 300 text: "click me" onClicked: {setModule( "Module1" ); readlistValues.readValues(modFinder.moduleIo); } } onSetModule: { modFinder.setModule(lblMsg) }
I had to create a property for each index value:
property string label1Text: ""
then assign them:
Item { id: readlistValues function readValues(anArray) { for (var i=0; i<32; i++) console.log("list: ", anArray[i]) label1Text = anArray[0] } }
Now 'anArray' contains my list!! And I can assign the text as I hoped.
Label { id: myLabel x: 270 y: 106 width: 100 height: 50 text: label1Text horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter }
I followed information on this page:
Data Type conversion Between QML and c++I'm sure I need to test this more, but I'm getting closer!
-
Hi @J-Hilk,
Thank you for your example - I apologize for not being more clear in what I'm trying to do. I have a GUI that I want to display the inputs and outputs of the modules of a PLC, so that when a user clicks the module button, the main page updates with that modules' list of I/O.
An over-simplified example:
I can't get a ListView to work because it displays the whole list at a time, so I am trying to access a QStringList by index and put each indexes text in a corresponding label.
I hope that better explains the problem I'm having!
Best regards.
like this ? (I only changed the main.qml from the previous example)
import QtQuick 2.9 import QtQuick.Window 2.2 import QtQuick.Controls 2.5 Window { visible: true width: 640 height: 480 title: qsTr("Hello World") id:root Button{ id:list1 anchors{ left:parent.left top:parent.top right:parent.horizontalCenter margins: 2 rightMargin: 1 } height: width / 3 text: qsTr("Set Model1") onClicked:cppListModel.myListModel = ["Left 1", "Left 2"] background: Rectangle{ color: cppListModel.myListModel[0] === "Left 1" ? "red" : "grey" } } Button{ id:list2 anchors{ left:parent.horizontalCenter top:parent.top right:parent.right margins: 2 leftMargin: 1 } height: width / 3 text: qsTr("Set Model2") onClicked:cppListModel.myListModel = ["Right 1", "Right 2"] background: Rectangle{ color: cppListModel.myListModel[0] === "Right 1" ? "red" : "grey" } } Text { id: entry1 text: cppListModel.myListModel[0] anchors{ left: parent.left right: parent.right top: list1.bottom margins: 2 } height: list1.height verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter } Text { id: entry2 text: cppListModel.myListModel[1] anchors{ left: parent.left right: parent.right top: entry1.bottom margins: 2 } height: list1.height verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter } }
-
wrote on 17 Jul 2019, 12:54 last edited by MScottM
Hi @J-Hilk,
That is the right behavior, but not the way I'm hoping to go about it. It looks like you are updating the list from the QML button?
In my 'real' application there will be something like 30 pieces of information to update on each button press, and like 20 possible modules (as I said - my example was over-simplified!). That is why I'm hoping to use a text file. Something like a config file that can be changed by a user as needed to update the I/O lists.
I think I can actually mark this one as solved, as I can now access the list from the QML side and set my labels' text. Now my issue is that even though the list updates on the c++ side, it doesn't change in QML after the first button press.
Shall I open a new question?
-
Hi @J-Hilk,
That is the right behavior, but not the way I'm hoping to go about it. It looks like you are updating the list from the QML button?
In my 'real' application there will be something like 30 pieces of information to update on each button press, and like 20 possible modules (as I said - my example was over-simplified!). That is why I'm hoping to use a text file. Something like a config file that can be changed by a user as needed to update the I/O lists.
I think I can actually mark this one as solved, as I can now access the list from the QML side and set my labels' text. Now my issue is that even though the list updates on the c++ side, it doesn't change in QML after the first button press.
Shall I open a new question?
@MScottM said in QStringList in QML?:
It looks like you are updating the list from the QML button
yes, but it doesn't matter what updates the list, as long as
setMyListModel
is calledI think I can actually mark this one as solved, as I can now access the list from the QML side and set my labels' text. Now my issue is that even though the list updates on the c++ side, it doesn't change in QML after the first button press.
hey, at least progress ;)
Shall I open a new question?
You can, but this could continue as well
Can you create a minimal compellable example? Should simplify things drastically 😉
-
wrote on 17 Jul 2019, 13:27 last edited by
I figured out what is happening! It's in this function:
QStringList moduleFinder::getIo(QString myModule) { //qDebug() << "my Module from QML" << myModule; int lines = ioList.length(); //qDebug() << "lines:" << lines; QString moduleId = myModule; for (int i=0;i<lines;i++) { //qDebug() << "IO List" << ioList.at(i); if (ioList.at(i).contains(moduleId)) { index = i; } } newIndex = index + 32; qDebug()<<"Index:" << index; qDebug()<<"New Index:" << newIndex; for (int y=index+1; y<newIndex+1; ++y) { // PROBLEM IS HERE //m_moduleIo is being appended with a new list each time m_moduleIo << ioList.at(y); // I need to check and clear it at each access, but not sure how!? qDebug() << "io List" << ioList.at(y); } emit moduleIoChanged(m_moduleIo); qDebug()<< "m_moduleIO" << m_moduleIo; return m_moduleIo; //emit moduleIoChanged(m_moduleIo); }
-
wrote on 17 Jul 2019, 22:46 last edited by
Update:
<smacks own forehead>
QStringList moduleFinder::getIo(QString myModule) { int lines = ioList.length(); QString moduleId = myModule; for (int i=0;i<lines;i++) { if (ioList.at(i).contains(moduleId)) { index = i; } } newIndex = index + 32; m_moduleIo.clear(); //<- RESET BEFORE EACH TIME THROUGH for (int y=index+1; y<newIndex+1; ++y) { m_moduleIo << ioList.at(y); qDebug() << "io List" << ioList.at(y); } emit moduleIoChanged(m_moduleIo); return m_moduleIo; }
It all works as I hoped now.
14/15