[solved] Newbie is confused.How to add dynamic data to TableView and parse through it send data to c++



  • I recently learned Model view programming in Qt. I want to implement a simple tableView.

    Table View

    Data will come from the user input so i have decided to implement my model also in qml.
    Here is the code.

    import QtQuick 2.3
    import QtQuick.Window 2.2
    import QtQuick.Controls 1.3
    import QtQuick.Layouts 1.1
    Window {
        visible: true
        width: Screen.width/2
        height: Screen.height/2
    
        ListModel{
            id:setTableModel
    
            ListElement{
                x_position: 100
                y_position: 200
                z_position: 300
                velocity: 200
                deceleration:300
                tracking_x: 200
                tracking_y:100
                tracking_z:200
            }
            ListElement{
                x_position: 100
                y_position: 200
                z_position: 300
                velocity: 200
                deceleration:300
                tracking_x: 200
                tracking_y:100
                tracking_z:200
            }
            ListElement{
                x_position: 100
                y_position: 200
                z_position: 300
                velocity: 200
                deceleration:300
                tracking_x: 200
                tracking_y:100
                tracking_z:200
            }
        }
    
        TableView{
            id:setTableView
            //        anchors.fill: parent
            model: setTableModel
            width: parent.width
            height: parent.height-buttons.height
            Layout.minimumWidth: 400
            Layout.minimumHeight: 240
            Layout.preferredWidth: 600
            Layout.preferredHeight: 400
            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: "deceleration"
                title: "D m/s2"
                width: 80
            }
            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
                }
            }
        }
        Row{
            id:buttons
            anchors.top: setTableView.bottom
            Button{
                id:addNewRowButton
    
                text: "ADD"
                onClicked: {
                   //I dont know whether this is the efficient way to add dynamic row to the table.any suggestions please
                    setTableModel.append({x_position: 0,
                                             y_position:0,
                                             z_position:0,
                                             velocity :0,
                                             deceleration:0,
                                             tracking_x:0,
                                             tracking_y:0,
                                             tracking_z:0}
                                         )
                }
            }
            Button{
                id:deleteRowButton
                text: "DELETE"
                onClicked: {
                    setTableModel.remove(setTableView.currentRow)
                }
            }
            Button{
                id:sendToCppButton
                text: "Send"
                onClicked: {
                    //            send all the data to cpp inorder to append to char array.
                    var rows = [];
                    for (var i = 0; i < setTableView.data.length; ++i) {
                        rows = rows.concat(setTableView.data[i]);
                        //don't know how to print the values on console and send the entire data to cpp side.
                        console.log("values are"+rows[i])
                    }
                }
            }
        }
    }
    
    

    Can any one tell me how to parse through each element and append some index number to it(so that c++ know from where it is coming) and send it to cpp side. Where the whole data is handled to send to contoller via Qtcpsocket.Thanks



  • Hi,

    I suggest to use JSON.stringify() to have a JSON string from each record in the model

    This code

    onClicked: {
        //            send all the data to cpp inorder to append to char array.
        var rows = [];
        for (var i = 0; i < setTableModel.count; ++i) {
            var obj = JSON.stringify(setTableModel.get(i));
            rows.push(obj)
        }
        console.log('We have ' + rows.length + ' rows')
        console.log(rows)
    }
    

    prints

    qml: We have 3 rows
    qml: [{"objectName":"","tracking_z":200,"tracking_y":100,"tracking_x":200,"deceleration":300,"velocity":200,"z_position":300,"y_position":200,"x_position":100},{"objectName":"","tracking_z":200,"tracking_y":100,"tracking_x":200,"deceleration":300,"velocity":200,"z_position":300,"y_position":200,"x_position":100},{"objectName":"","tracking_z":200,"tracking_y":100,"tracking_x":200,"deceleration":300,"velocity":200,"z_position":300,"y_position":200,"x_position":100}]
    

    In C++ you'll receive a QList of QStrings that you can easily parse using the JSON module



  • @mcosta
    Thanks a lot for the reply. I really don't know how to parse using the JSON module. I tried this way as per your hint.
    In qml i have sent the whole rows to the backend.

    var rows = [];
     for (var i = 0; i < setTableModel.count; ++i) {
     var obj = JSON.stringify(setTableModel.get(i));
     rows.push(obj);
     }
    SetTableDataHandling.datafromsetTableQml(rows);//Is this the right way to send?
    

    where SetTableDataHandling is a registered c++ class.
    In c++:

    void SetTableDataHandling::datafromsetTableQml(QList<QString> var) //Is this the right way to do?
    {
      //How exactly i should parse the data?
       qDebug()<<"received data "<<var.at(2);
    }
    

    Thanks.



  • Hi,

    you should use QJsonDocument to parse JSON strings



  • @mcosta
    Is it correct the way how I access the Qml data in cpp?
    void SetTableDataHandling::datafromsetTableQml(QList<QString> var) //Is this the right way to do?


  • Moderators

    @vishnu Actually you can directly access QML ListModel from C++. It can be casted into QAbstractListModel. Here is an example of how to access the data from C++

    QObject* root = engine.rootObjects().first(); //get the root object as usual
    QObject* list = root->findChild<QObject*>("myListview"); //get the ListView
    
    QVariant qmlmodel = list->property("model"); //access model property of ListView
    QAbstractListModel *model = qvariant_cast<QAbstractListModel *>(qmlmodel); //convert to QAbstractListModel
    
    int rows = model->rowCount(); //get number of rows from model
    
    //iterate through the model
    for (int i = 0; i<rows; i++) {
        for(int j = 0; j<model->roleNames().count(); j++) { //get the roles count
            qDebug() <<  model->index(i, 0).data(j); //get the actual data using roles
        }
    }
    
    //accessing roles
    for(int j = 0; j<model->roleNames().count(); j++) {
        qDebug() << model->roleNames()[j];
    }
    

    P.S: In your case it would be TableView.



  • @p3c0
    Thanks a lot man!!!
    But how do i get engine which is instanstiated in main.cpp to the function where I have to handle the data? Because engine is not declared in this scope right? Thanks



  • @p3c0
    I just tried in main.cpp but I ended with the following error.

    ASSERT: "!isEmpty()" in file ....\Qt\Qt5.4.1\5.4\mingw491_32\include/QtCore/qlist.h, line 292
    Invalid parameter passed to C runtime function.
    Invalid parameter passed to C runtime function.

    Main.cpp

    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
        SetTableDataHandling  setTableDataHandling;
        auto root_context = engine.rootContext();
        root_context->setContextProperty("SetTableDataHandling",&setTableDataHandling);
    
        //********
        QObject* root = engine.rootObjects().first();
    //    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
    
    //    int rows = model->rowCount(); //get number of rows from model
    
    //    //iterate through the model
    //    for (int i = 0; i<rows; i++) {
    //        for(int j = 0; j<model->roleNames().count(); j++) { //get the roles count
    //            qDebug() <<  model->index(i, 0).data(j); //get the actual data using roles
    //        }
    //    }
    
        //
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
        return app.exec();
    }
    

  • Moderators

    @vishnu
    QObject* root = engine.rootObjects().first();
    do this after loading the QML.

    But how do i get engine which is instanstiated in main.cpp to the function where I have to handle the data? Because engine is not declared in this scope right? Thanks

    Pass the pointer or reference of engine to that function.



  • @p3c0
    Man!!! you're are awesome awesomeeeee!!!! Thanks a lot.



  • @p3c0
    May I know why the roles and data are in reverse order?
    What i get is:
    "tracking_z"
    "tracking_y"
    "tracking_x"
    "deceleration"
    "velocity"
    "z_position"
    "y_position"
    "x_position"
    But it should be in reverse order.
    what i expect the data at
    qDebug() << model->index(i, 0).data(j)
    is the first row and first column from left side of TableView. But It is starting from right side. How do I make it correct?Thanks


  • Moderators

    @vishnu That is completely internal. The processing of roles and properties by the engine cannot be controlled.
    To correct it the only way is to read the properties in reverse order in the loop :)



  • @p3c0
    I am still getting the error.
    ASSERT: "!isEmpty()" in file ......\Qt5.4.1\5.4\mingw491_32\include/QtCore/qlist.h, line 292
    Invalid parameter passed to C runtime function.
    Invalid parameter passed to C runtime function.
    My main.cpp:

    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);
        QQmlApplicationEngine engine;
        TCPCommunicationPort tcpCommunicationPort;
        auto root_context = engine.rootContext();
        root_context->setContextProperty("tcpCommunicationPort",&tcpCommunicationPort);
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
        QObject* root = engine.rootObjects().first();// error at this point
        return app.exec();
    }
    

    The same main code was working fine in another project but When i copied the same in new project it's again saying the same error. I have loaded main.qml before
    QObject* root = engine.rootObjects().first();
    May i know what's the mistake?


  • Moderators

    @vishnu Can you post the QML part ? i.e main.qml



  • @p3c0
    main.qml

    import QtQuick 2.3
    import QtQuick.Window 2.2
    import QtQuick.Controls 1.3
    
    Window{
        id:window
        width: Screen.width
        height: Screen.height
        visible: true
    
        Item{
            id:mainUI
            anchors.fill: parent
            Header{
                id:header
            }
            CentralView{
                id:centralView
                anchors.top: header.bottom
                anchors.bottom: footer.top
            }
            //Model
            SetTable{
                id:setTable
                anchors.top: header.bottom
                anchors.bottom: footer.top
                visible: false
            }
            Footer {
                id: footer
                anchors.bottom: parent.bottom
            }
            states: [
                State {
                    name: "MainView"
                    PropertyChanges {target: centralView;cycRegVisible:false; ctrlReg1Visible:false;ctrlReg2Visible:false;cmodeRegVisible:false;directModeRegVisible:false}
                    PropertyChanges {target: footer;backButtonvisible:false; }
                },
                //setTable view state
                State {
                    name: "SetTableView"
                    PropertyChanges {target: centralView;centralViewVisible:false;}
                    PropertyChanges {target: setTable;visible:true;}
                    PropertyChanges {target: footer;forwardButtonvisible:false;}
                },
                State {
                    name: "CyclicRegisterView"
                    PropertyChanges {target: centralView;cycRegVisible:true }
                    PropertyChanges {target: footer;backButtonvisible:true}
                    PropertyChanges {target: centralView;ctrlReg1Visible:false }
                    PropertyChanges {target: centralView;ctrlReg2Visible:false }
                    PropertyChanges {target: centralView;cmodeRegVisible:false }
                    PropertyChanges {target: centralView;directModeRegVisible:false }
                    PropertyChanges {target: centralView;trackingModeRegVisible:false }
                    PropertyChanges {target: centralView;displayViewVisible:false }
                },
                State {
                    name: "ControlRegister1View"
                    PropertyChanges {target: centralView;cycRegVisible:false;ctrlReg1Visible:true;ctrlReg2Visible:false;cmodeRegVisible:false;directModeRegVisible:false}
                    PropertyChanges {target: centralView;trackingModeRegVisible:false }
                    PropertyChanges {target: footer;backButtonvisible:true; }
                    PropertyChanges {target: centralView;displayViewVisible:false }
                },
                State {
                    name: "ControlRegister2View"
                    PropertyChanges {target: centralView;cycRegVisible:false;ctrlReg1Visible:false;ctrlReg2Visible:true;cmodeRegVisible:false;directModeRegVisible:false}
                    PropertyChanges {target: centralView;trackingModeRegVisible:false }
                    PropertyChanges {target: footer;backButtonvisible:true; }
                    PropertyChanges {target: centralView;displayViewVisible:false }
                },
                State {
                    name: "OperationModeRegisterView"
                    PropertyChanges {target: centralView;cycRegVisible:false;ctrlReg1Visible:false;ctrlReg2Visible:false;cmodeRegVisible:true;directModeRegVisible:false }
                    PropertyChanges {target: centralView;trackingModeRegVisible:false ;homingModeRegVisible:false}
                    PropertyChanges {target: footer;backButtonvisible:true; }
                    PropertyChanges {target: centralView;displayViewVisible:false }
                },
                State {
                    name: "DirectModeRegisterView"
                    PropertyChanges {target: centralView;cycRegVisible:false;ctrlReg1Visible:false;ctrlReg2Visible:false;cmodeRegVisible:false;directModeRegVisible:true}
                    PropertyChanges {target: centralView;trackingModeRegVisible:false ;homingModeRegVisible:false}
                    PropertyChanges {target: footer;backButtonvisible:true; }
                    PropertyChanges {target: centralView;displayViewVisible:false }
                },
                State {
                    name: "SetTableModeRegisterView"
                    PropertyChanges {target: centralView;cycRegVisible:false;ctrlReg1Visible:false;ctrlReg2Visible:false;cmodeRegVisible:false;directModeRegVisible:false}
                    PropertyChanges {target: centralView;setTableModeRegVisible:true;trackingModeRegVisible:false;homingModeRegVisible:false}
                    PropertyChanges {target: footer;backButtonvisible:true; }
                    PropertyChanges {target: centralView;displayViewVisible:false }
                },
                State {
                    name: "TrackingModeRegisterView"
                    PropertyChanges {target: centralView;cycRegVisible:false;ctrlReg1Visible:false;ctrlReg2Visible:false;cmodeRegVisible:false;directModeRegVisible:false}
                    PropertyChanges {target: centralView;setTableModeRegVisible:false;trackingModeRegVisible:true;homingModeRegVisible:false}
                    PropertyChanges {target: footer;backButtonvisible:true; }
                    PropertyChanges {target: centralView;displayViewVisible:false }
                },
                State {
                    name: "HomingModeRegisterView"
                    PropertyChanges {target: centralView;cycRegVisible:false;ctrlReg1Visible:false;ctrlReg2Visible:false;cmodeRegVisible:false;directModeRegVisible:false}
                    PropertyChanges {target: centralView;setTableModeRegVisible:false;trackingModeRegVisible:false;homingModeRegVisible:true}
                    PropertyChanges {target: footer;backButtonvisible:true; }
                    PropertyChanges {target: centralView;displayViewVisible:false }
                },
                State {
                    name: "JoggingModeRegisterView"
                    PropertyChanges {target: centralView;cycRegVisible:false;ctrlReg1Visible:false;ctrlReg2Visible:false;cmodeRegVisible:false;directModeRegVisible:false}
                    PropertyChanges {target: centralView;setTableModeRegVisible:false;trackingModeRegVisible:false;homingModeRegVisible:false;jogginModeRegVisible:true}
                    PropertyChanges {target: footer;backButtonvisible:true; }
                    PropertyChanges {target: centralView;displayViewVisible:false }
                },
                State {
                    name: "SAcyclicRegisterView"
                    PropertyChanges {target: centralView;cycRegVisible:false;ctrlReg1Visible:false;ctrlReg2Visible:false;cmodeRegVisible:false;directModeRegVisible:false}
                    PropertyChanges {target: centralView;setTableModeRegVisible:false;trackingModeRegVisible:false;homingModeRegVisible:false;jogginModeRegVisible:false}
                    PropertyChanges {target: footer;backButtonvisible:true; }
                    PropertyChanges {target: centralView;displayViewVisible:true;controlViewVisible:false;sAcycRegVisible:true }
                },
                State {
                    name: "StatusRegister1View"
                    PropertyChanges {target: centralView;cycRegVisible:false;ctrlReg1Visible:false;ctrlReg2Visible:false;cmodeRegVisible:false;directModeRegVisible:false}
                    PropertyChanges {target: centralView;setTableModeRegVisible:false;trackingModeRegVisible:false;homingModeRegVisible:false;jogginModeRegVisible:false}
                    PropertyChanges {target: footer;backButtonvisible:true; }
                    PropertyChanges {target: centralView;displayViewVisible:true;controlViewVisible:false;sAcycRegVisible:false;statusReg1Visible:true }
                },
                State {
                    name: "StatusRegister2View"
                    PropertyChanges {target: centralView;cycRegVisible:false;ctrlReg1Visible:false;ctrlReg2Visible:false;cmodeRegVisible:false;directModeRegVisible:false}
                    PropertyChanges {target: centralView;setTableModeRegVisible:false;trackingModeRegVisible:false;homingModeRegVisible:false;jogginModeRegVisible:false}
                    PropertyChanges {target: footer;backButtonvisible:true; }
                    PropertyChanges {target: centralView;displayViewVisible:true;controlViewVisible:false;sAcycRegVisible:false;statusReg2Visible:true }
                },
                State {
                    name: "StatusRegister3View"
                    PropertyChanges {target: centralView;cycRegVisible:false;ctrlReg1Visible:false;ctrlReg2Visible:false;cmodeRegVisible:false;directModeRegVisible:false}
                    PropertyChanges {target: centralView;setTableModeRegVisible:false;trackingModeRegVisible:false;homingModeRegVisible:false;jogginModeRegVisible:false}
                    PropertyChanges {target: footer;backButtonvisible:true; }
                    PropertyChanges {target: centralView;displayViewVisible:true;controlViewVisible:false;sAcycRegVisible:false;statusReg3Visible:true }
                },
                State {
                    name: "SOperationModeRegisterView"
                    PropertyChanges {target: centralView;cycRegVisible:false;ctrlReg1Visible:false;ctrlReg2Visible:false;cmodeRegVisible:false;directModeRegVisible:false}
                    PropertyChanges {target: centralView;setTableModeRegVisible:false;trackingModeRegVisible:false;homingModeRegVisible:false;jogginModeRegVisible:false}
                    PropertyChanges {target: footer;backButtonvisible:true; }
                    PropertyChanges {target: centralView;displayViewVisible:true;controlViewVisible:false;sAcycRegVisible:false;sOperationRegVisible:true }
                },
                State {
                    name: "SDirectModeRegisterView"
                    PropertyChanges {target: centralView;cycRegVisible:false;ctrlReg1Visible:false;ctrlReg2Visible:false;cmodeRegVisible:false;directModeRegVisible:false}
                    PropertyChanges {target: centralView;setTableModeRegVisible:false;trackingModeRegVisible:false;homingModeRegVisible:false;jogginModeRegVisible:false}
                    PropertyChanges {target: footer;backButtonvisible:true; }
                    PropertyChanges {target: centralView;displayViewVisible:true;controlViewVisible:false;sAcycRegVisible:false;sDirectModeRegVisible:true }
                },
                State {
                    name: "SSetTableModeRegisterView"
                    PropertyChanges {target: centralView;cycRegVisible:false;ctrlReg1Visible:false;ctrlReg2Visible:false;cmodeRegVisible:false;directModeRegVisible:false}
                    PropertyChanges {target: centralView;setTableModeRegVisible:false;trackingModeRegVisible:false;homingModeRegVisible:false;jogginModeRegVisible:false}
                    PropertyChanges {target: footer;backButtonvisible:true; }
                    PropertyChanges {target: centralView;displayViewVisible:true;controlViewVisible:false;sAcycRegVisible:false;sSetTableModeRegVisible:true }
                },
                State {
                    name: "STrackingModeRegisterView"
                    PropertyChanges {target: centralView;cycRegVisible:false;ctrlReg1Visible:false;ctrlReg2Visible:false;cmodeRegVisible:false;directModeRegVisible:false}
                    PropertyChanges {target: centralView;setTableModeRegVisible:false;trackingModeRegVisible:false;homingModeRegVisible:false;jogginModeRegVisible:false}
                    PropertyChanges {target: footer;backButtonvisible:true; }
                    PropertyChanges {target: centralView;displayViewVisible:true;controlViewVisible:false;sAcycRegVisible:false;sTtrackingModeRegVisible:true }
                },
                State {
                    name: "SHomingRegisterView"
                    PropertyChanges {target: centralView;cycRegVisible:false;ctrlReg1Visible:false;ctrlReg2Visible:false;cmodeRegVisible:false;directModeRegVisible:false}
                    PropertyChanges {target: centralView;setTableModeRegVisible:false;trackingModeRegVisible:false;homingModeRegVisible:false;jogginModeRegVisible:false}
                    PropertyChanges {target: footer;backButtonvisible:true; }
                    PropertyChanges {target: centralView;displayViewVisible:true;controlViewVisible:false;sAcycRegVisible:false;sHomingModeRegVisible:true }
                },
                State {
                    name: "SJoggingRegisterView"
                    PropertyChanges {target: centralView;cycRegVisible:false;ctrlReg1Visible:false;ctrlReg2Visible:false;cmodeRegVisible:false;directModeRegVisible:false}
                    PropertyChanges {target: centralView;setTableModeRegVisible:false;trackingModeRegVisible:false;homingModeRegVisible:false;jogginModeRegVisible:false}
                    PropertyChanges {target: footer;backButtonvisible:true; }
                    PropertyChanges {target: centralView;displayViewVisible:true;controlViewVisible:false;sAcycRegVisible:false;sJogginModeRegVisible:true }
                }
            ]
            state: "MainView"
            Connections{
                target: centralView;
                onAcyclicButtonClicked:{
                    //                console.log("switching to CyclicRegisterView")
                    mainUI.state="CyclicRegisterView"
    
                }
                onControlRegister1ButtonClicked:{
                    //                console.log("switching to Control Register1View")
                    mainUI.state="ControlRegister1View"
                }
                onControlRegister2ButtonClicked:{
                    //                console.log("switching to Control Register2View")
                    mainUI.state="ControlRegister2View"
                }
                onOperationModeRegisterClicked:{
                    //                console.log("switching to CMODE or operation mode register view")
                    mainUI.state="OperationModeRegisterView"
                }
                onDirectModeRegisterClicked:{
                    //                console.log("switching to direct mode register view")
                    mainUI.state="DirectModeRegisterView"
                }
                onSetTableModeRegisterClicked:{
                    //                console.log("switching to settable mode register view")
                    mainUI.state="SetTableModeRegisterView"
                }
                onTrackingModeRegisterClicked:{
                    //                console.log("switching to trakingmode register view")
                    mainUI.state="TrackingModeRegisterView"
                }
                onHomingModeRegisterClicked:{
                    //                console.log("switching to homing register view")
                    mainUI.state="HomingModeRegisterView"
                }
                onJoggingModeRegisterClicked:{
                    //                console.log("switching to joggin register view")
                    mainUI.state="JoggingModeRegisterView"
                }
                onSAcyclicButtonClicked:{
                    //                console.log("switching to display acyclic register view")
                    mainUI.state="SAcyclicRegisterView"
                }
                onSStatusRegister1ButtonClicked:{
                    mainUI.state="StatusRegister1View"
                }
                onSStatusRegister2ButtonClicked:{
                    mainUI.state="StatusRegister2View"
                }
                onSStatusRegister3ButtonClicked:{
                    mainUI.state="StatusRegister3View"
                }
                onSOperationModeRegisterClicked:{
                    mainUI.state="SOperationModeRegisterView"
                }
                onSDirectModeRegisterClicked:{
                    mainUI.state="SDirectModeRegisterView"
                }
                onSSetTableModeRegisterClicked:{
                    mainUI.state="SSetTableModeRegisterView"
                }
                onSTrackingModeRegisterClicked:{
                    mainUI.state="STrackingModeRegisterView"
                }
                onSHomingModeRegisterClicked:{
                    mainUI.state="SHomingRegisterView"
                }
                onSJoggingModeRegisterClicked:{
                    mainUI.state="SJoggingRegisterView"
                }
            }
            Connections{
                target: footer
                onBackButtoncliked:{
                    //                console.log("switching to MainView")
                    mainUI.state="MainView"
                }
                onForwardButtonClicked:{
                    mainUI.state="SetTableView"
                }
            }
        }
    }
    

    Sorry for the lengthy one. my model is in SetTable.qml

    import 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: 1000
                y_position: 200
                z_position: 300
                velocity: 28
                acceleration:34
                deceleration:14
                tool:1
                tracking_x: 400
                tracking_y:500
                tracking_z:5
            }
            ListElement{
                x_position: 1000
                y_position: 200
                z_position: 300
                velocity: 28
                acceleration:34
                deceleration:14
                tool:1
                tracking_x: 400
                tracking_y:500
                tracking_z:5
            }
            ListElement{
                x_position: 100
                y_position: 200
                z_position: 300
                velocity: 28
                acceleration:34
                deceleration:14
                tool:1
                tracking_x: 400
                tracking_y:500
                tracking_z:555
            }
        }
    
        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
                }
            }
        }
    }
    

    But the same piece of code as main.cpp is working fine in another project. I think something is wrong with my main.qml. May i know what's the mistake? Thanks


  • Moderators

    @vishnu No idea. Seems closer to this QTBUG-44859.
    Can you try trimming down the main.qml i.e removing some component and then executing ?



  • @p3c0
    Okay, Any other way to access the TableView model in C++ side?


  • Moderators

    @vishnu AFAIK. no. But that error is not related to TableView or ListModel.



  • @p3c0
    Got it.The error was due to the wrong import statement in qml.
    Now How do I capture the changes?
    If reading the entire model is the solution (ofcourse not efficient).
    How can I call this public slot getModel when ever there is a change in TableView in qml? What is the signal I get from the model/view which tells me that there is a change ?

    void TCPCommunicationPort::getModel(QQmlApplicationEngine &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
    .....//data is handled here
    

  • Moderators

    @vishnu As we casted it to QAbstractListModel we can connect to its signal dataChanged from C++. Thus when anything changes the slot will be called.

    QAbstractListModel *model = qvariant_cast<QAbstractListModel *>(qmlmodel);
    QObject::connect(model,SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
                         &myclass,SLOT(onDataChanged(QModelIndex,QModelIndex,QVector<int>)));
    

    Access the changed data in slot

    void MyClass::onDataChanged(const QModelIndex &topLeft, 
                 const QModelIndex &bottomRight, const QVector<int> &roles)
    {
        qDebug() << "Data Changed :" << topLeft.data(roles[0]) << topLeft.data(roles[1]);
    }
    


  • @p3c0
    I don't know why but the SLOT is not called when the data changes.
    I did the connection in main itself.
    main.qml

    QQmlApplicationEngine 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?


  • Moderators

    @vishnu

    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 use onDataChanged 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.qml

    import 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
                }
            }
        }
    }
    

  • Moderators

    @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


  • Moderators

    @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


  • Moderators

    @vishnu

    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
                }
            }
    

  • Moderators

    @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}
                                             )
                    }
                }
    

  • Moderators

    @vishnu No that is not updating. That wont invoke the data changed signal.
    As said earlier if you use append or remove 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.


  • Moderators

    @vishnu Keep your code with append and remove as it is. It just adds and removes the rows. Now to update the already added elements in ListModel use set.
    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 this

    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}
                                             )
    //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});
    

  • Moderators

    @vishnu See

    • set is used to update the ListModel
    • 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 in onAccepted handler of TextInput
      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.


  • Moderators

    @vishnu

    • Can I access this model in onDataChanged SLOT?
      -Yes. The QModelIndex also returns the model. Use topLeft.model()

    • How to get the role name for which corresponding value is changed.
      -Once you get the model using above method use roleNames().
      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.


  • Moderators

    @vishnu

    perfect.served my purpose :) but inefficient solution :(.

    What inefficient ?


Log in to reply
 

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