[solved] Newbie is confused.How to add dynamic data to TableView and parse through it send data to c++
-
@p3c0
I don't know why but the SLOT is not called when the data changes.
I did the connection in main itself.
main.qmlQQmlApplicationEngine engine; TCPCommunicationPort tcpCommunicationPort; auto root_context = engine.rootContext(); root_context->setContextProperty("tcpCommunicationPort",&tcpCommunicationPort); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); // tcpCommunicationPort.getModel(engine); QObject* root = engine.rootObjects().first(); //get the root object as usual QObject* list = root->findChild<QObject*>("setTableView"); //get the ListView QVariant qmlmodel = list->property("model"); //access model property of ListView QAbstractListModel *model = qvariant_cast<QAbstractListModel *>(qmlmodel); //convert to QAbstractListModel QObject::connect(model,SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)), &tcpCommunicationPort,SLOT(onDataChanged(QModelIndex,QModelIndex,QVector<int>)));
In header file
public slots: void onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles);
May i know why the slot is not called?I even don't know whether the signal is raised or not.How to know whether the signal is emitted not in this case?
-
May i know why the slot is not called?I even don't know whether the signal is raised or not.How to know whether the signal is emitted not in this case?
Since you are using
ListModel
useonDataChanged
signal handler.ListModel { id: myModel onDataChanged: console.log("Data Changed") }
thus verify whether the data is changed.
-
@p3c0
nice hint. unfortunatelly onDataChanged singal is not emitted. when ever I am changing data,adding new row. That means problem is on my QML side.Again this is code for my model,View:
setTable.qmlimport QtQuick 2.3 import QtQuick.Window 2.2 import QtQuick.Controls 1.3 import QtQuick.Layouts 1.1 Rectangle { id:root anchors.fill: parent Row{ id:buttons anchors.top: root.top Button{ id:addNewRowButton text: "ADD" onClicked: { setTableModel.append({x_position: 0, y_position:0, z_position:0, velocity :0, acceleration:0, deceleration:0, tool:0, tracking_x:0, tracking_y:0, tracking_z:0} ) } } Button{ id:deleteRowButton text: "DELETE" onClicked: { setTableModel.remove(setTableView.currentRow) } } } ListModel{ id:setTableModel ListElement{ x_position: 0 y_position: 300 z_position: 500 velocity: 100 acceleration:100 deceleration:0 tool:0 tracking_x: 0 tracking_y:0 tracking_z:0 } onDataChanged: { console.log("Data changed") } } TableView{ id:setTableView objectName: "setTableView" model: setTableModel width: parent.width height: parent.height-buttons.height Layout.minimumWidth: 400 Layout.minimumHeight: 240 Layout.preferredWidth: 600 Layout.preferredHeight: 400 anchors.top: buttons.bottom TableViewColumn { role: "x_position" title: "X mm" width: 80 } TableViewColumn { role: "y_position" title: "Y mm" width: 80 } TableViewColumn { role: "z_position" title: "Z mm" width: 80 } TableViewColumn { role: "velocity" title: "V m/s" width: 80 } TableViewColumn { role: "acceleration" title: "A m/s2" width: 80 } TableViewColumn { role: "deceleration" title: "D m/s2" width: 80 } TableViewColumn { role: "tool" title: "Tool" width: 80 delegate: TextInput { anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter renderType: Text.NativeRendering validator: IntValidator {bottom: 0; top: 1;} text: styleData.value } } TableViewColumn { role: "tracking_x" title: "Tx mm" width: 80 } TableViewColumn { role: "tracking_y" title: "Ty mm" width: 80 } TableViewColumn { role: "tracking_z" title: "Tz mm" width: 80 } itemDelegate: Item { TextInput { anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter renderType: Text.NativeRendering text: styleData.value } } } }
-
@vishnu AFAICS You are just adding and removing the data but not updating it. In this case dataChanged wont be called.
-
@p3c0
Any hint or example on how to update the data? Thanks a lot -
@vishnu Make use rowsInserted of rowsRemoved signals. Connect them to their respective slots as shown previously for
dataChanged
. -
@p3c0
I have already added 3 rows with default value. when ever I change default value to someother value. I am not getting the updated value to c++ side.
QObject::connect(model,SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)), &myclass,SLOT(onDataChanged(QModelIndex,QModelIndex,QVector<int>)));
This is not working? As you said since I am not updating the model, just appending and removing the rows.I feel like there has to be done more in my QML part.May I know what is wrong or missing in my Model and View (QML) ?Thanks -
I have already added 3 rows with default value. when ever I change default value to someother value. I am not getting the updated value to c++ side.
how are you changing the default value ?
-
@p3c0
I can change my default values because my delegate is a TextInput.TableViewColumn { role: "tool" title: "Tool" width: 80 delegate: TextInput { anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter renderType: Text.NativeRendering validator: IntValidator {bottom: 0; top: 1;} text: styleData.value } }
-
@vishnu Im asking how do you change the items added in
ListModel
? That signal will only be updated only when you update the existing items in the model.
For eg:ListModel { id: myModel ListElement { name: "abc" age: 12 } onDataChanged: console.log("Changed") } //updating the list model myModel.set(0, { "name" : "xyz" } )
So here the signal dataChanged will be triggered and hence the slot onDataChanged in QML will be invoked. Same will work for C++ slot too.
Now in your earlier code you are just adding and removing the rows so those signals (mentioned earlier) will be triggered.
-
@p3c0
I am no where doing that kind of updating. I am assuming that ListModel.append method does updating the model as well as view.Button{ id:addNewRowButton text: "ADD" onClicked: { setTableModel.append({"x_position": 0, "y_position":0, "z_position":0, "velocity":0, "acceleration":0, "deceleration":0, "tool":0, "tracking_x":0, "tracking_y":0, "tracking_z":0} ) } }
-
@vishnu No that is not updating. That wont invoke the data changed signal.
As said earlier if you useappend
orremove
use rowsInserted or rowsRemoved signals repectively. -
@p3c0
you are right. This works perfect. I can see the data in c++ when ever a new row is added.QObject::connect(model,SIGNAL(rowsInserted(QModelIndex,int,int)), &tcpCommunicationPort,SLOT(onRowsInserted(QModelIndex,int,int)));
But when one of item in the Row is changed I can't see the new data in c++.So that means only Set/setproperty of ListModel will invoke the data changed signal. That mean My qml code is wrong if i want dataChangedsignal.
I changed my TableView like this:TableView{ id:setTableView objectName: "setTableView" model: { setTableModel.set(0,{"x_position": 0, "y_position":300, "z_position":500, "velocity":0, "acceleration":0, "deceleration":0, "tool":0, "tracking_x":0, "tracking_y":0, "tracking_z":0}); setTableModel.set(1,{"x_position": 0, "y_position":400, "z_position":800, "velocity":0, "acceleration":0, "deceleration":0, "tool":0, "tracking_x":0, "tracking_y":0, "tracking_z":0}) }
Now the entire view if gone. I cannot add anymore rows.That means what I have done is wrong.But don't know what to do.
Also If the user changes some value in any of the times.how can i know which value is changed? TableView has onClicked signal I can get the current row ,and delegate has access to the properties styleData.row - the index of the row ; styleData.column - the index of the column. Don't know how to make use of them.
Can you please tell me what exactly have to be done on my QML side. Should i change my delegate or View or Model code?Thanks. -
@vishnu Keep your code with
append
andremove
as it is. It just adds and removes the rows. Now to update the already added elements inListModel
useset
.
So,append -> rowsInserted remove -> rowsRemoved update i.e set -> dataChanged
-
@p3c0
I got the meaning what your saying but Where and how exactly I should do that set.
For eg: should I do like thisButton{ id:addNewRowButton text: "ADD" onClicked: { setTableModel.append({"x_position": 0, "y_position":0, "z_position":0, "velocity":0, "acceleration":0, "deceleration":0, "tool":0, "tracking_x":0, "tracking_y":0, "tracking_z":0} ) //ofcourse index is not defined, May be I make a property and increment it when even I add new row. setTableModel.set(index,{"x_position": 0, "y_position":0, "z_position":0, "velocity":0, "acceleration":0, "deceleration":0, "tool":0, "tracking_x":0, "tracking_y":0, "tracking_z":0}) }
How about defalut values where should i set them?
Is It in Tableview:this went totally wrong.id:setTableView objectName: "setTableView" model: { setTableModel.set(0,{"x_position": 0, "y_position":300, "z_position":500, "velocity":0, "acceleration":0, "deceleration":0, "tool":0, "tracking_x":0, "tracking_y":0, "tracking_z":0});
-
@vishnu See
set
is used to update theListModel
- since you have used
TextInput
to allow user to update the data you need a way to update the model from this. This can be done inonAccepted
handler ofTextInput
So to sum up, for eg:
delegate: TextInput { anchors.fill: parent text: styleData.value onAccepted: { myModel.set( styleData.row, { title: text } ) //updates the role name "title" with updated text of TextInput } }
-
@p3c0
Thanks for the explanation.Now I am not able to know which role is changed.
As you said I did like this in QML.TableViewColumn { role: "tracking_z" title: "Tz mm" delegate: TextInput { validator: IntValidator {} text: styleData.value onAccepted: { setTableModel.set(styleData.row,{"tracking_z":parseInt(text)}) } }
For each column view I have a separate delegate because the IntValidator differs for each role.When ever there is datachanged this SLOT is called successfully.
void TCPCommunicationPort::onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles) { qDebug() << "row changed"<<topLeft.row();//getting the row number qDebug() << "column changed"<<topLeft.column();//this is always zero.I don't know why. QVariant newValue = topLeft.data(roles[0]); qDebug() << "Data Changed in cpp"<<newValue.toInt();//Getting the value where ever i change in the tableView. //How to get the role name for which corresponding value is changed. }
Main problem is how to go the position where I have saved the tabledata to a position in Qbytearray.Can I access this model in onDataChanged SLOT?
QAbstractListModel *model = qvariant_cast<QAbstractListModel *>(qmlmodel); //convert to QAbstractListModel
Atleast I will try to read the whole new data(ofcourse it is insufficient) but my purpose is served. -
-
Can I access this model in onDataChanged SLOT?
-Yes. TheQModelIndex
also returns the model. UsetopLeft.model()
-
How to get the role name for which corresponding value is changed.
-Once you get the model using above method useroleNames()
.
topLeft.model()->roleNames()[roles[0]]
. This will give exact role name. -
Atleast I will try to read the whole new data(ofcourse it is insufficient) but my purpose is served.
-Ok. Would't that be unnecessary ?
-
-
@p3c0
perfect.served my purpose :) but inefficient solution :(.- Atleast I will try to read the whole new data(ofcourse it is insufficient) but my purpose is served.
-Ok. Would't that be unnecessary ?
because I have to send the data by array of char and I have saved the data from Tableview to char array like this:
char m_senddataBuffer[3256]={0};//I know the max size char *positionValue; positionValue = &m_senddataBuffer[56];//created a pointer to a particular position. int count=0; for (int i = 0; i<rows; i++) { for(int j = model->roleNames().count()-1; j>=0; j--) { //get the roles count QVariant rowData= model->index(i, 0).data(j); //get the actual data using roles QString rolename = model->roleNames()[j]; int value =rowData.toInt(); //qDebug()<<" row"<<i << "role name"<<rolename<< "value "<<value; if(!QString::compare(rolename,"x_position",Qt::CaseInsensitive)) { qDebug()<<"x_position is running"<<++count; value=value*1000; //int to char array *(positionValue++) = (value) & 0xFF; *(positionValue++) = (value >> 8) & 0xFF; *(positionValue++) = (value >> 16) & 0xFF; *(positionValue++) = (value >> 24) & 0xFF; } //and so on...
I just copy pasted the same code in onDataChanged SLOT. I thought of writing a function readModel(QAbstractItemModel model). but the typecased model is of type QAbstractListModel.So I have done like this. Any improvements can be done. Please let me know.
- Atleast I will try to read the whole new data(ofcourse it is insufficient) but my purpose is served.
-