Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Using 2 different ListModels with 2 different ComboBoxes
Forum Updated to NodeBB v4.3 + New Features

Using 2 different ListModels with 2 different ComboBoxes

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
14 Posts 2 Posters 863 Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • G Offline
    G Offline
    gabor53
    wrote on last edited by
    #1

    Hi,

    In the same page I have two separate ComboBoxes. Each ComboBox is populated from a different table from an SQLite db. The first ComboBox looks like this:

     QQuick2.ComboBox {
                id: medicationCombo
                width: backgrnd.width / 2.7
                height: dp(25)
                anchors.bottom: medName.bottom
                anchors.left: medName.right
                anchors.leftMargin: dp(15)
                font.pixelSize: 16
                editable: true
                textRole: "MednameField"
                focus: true
    
                //Displaying the first item from the db.
                currentIndex: 0
    
                model: ListModel {
                    id: listModel2
                }
    
                delegate: QQuick2.ItemDelegate {
                    width: medicationCombo.width
                    height: medicationCombo.height
    
                    //Defining the items in the dropdown list
                    Text {
                        id: medTxt
                        text: model.MednameField //This is not working.
                        font.pixelSize: 18
                        color: "#00008b"
                        anchors.verticalCenter: parent.verticalCenter
                    }
    
                    onClicked: medicationCombo.currentIndex = index
                    highlighted: medicationCombo.highlightedIndex === index
                }
    

    The second one:

    QQuick2.ComboBox {
                id: patientCombo
                width: backgrnd.width / 2.7
                height: dp(25)
                anchors.bottom: name.bottom
                anchors.left: name.right
                anchors.leftMargin: dp(15)
                font.pixelSize: 16
                editable: true
                textRole: "patientField"
                focus: true
    
                //Displaying the first item from the db.
                currentIndex: 0
    
                model: ListModel {
                    id: listModel
                }
    
                delegate: QQuick2.ItemDelegate {
                    width: patientCombo.width
                    height: patientCombo.height
    
                    //Defining the items in the dropdown list
                    Text {
                        id: ptnts
                        text: model.patientField
                        font.pixelSize: 18
                        color: "#00008b"
                        anchors.verticalCenter: parent.verticalCenter
                    }
    

    The db file:

    //Creating or opening the database
    function dbInit() {
        var db = LocalStorage.openDatabaseSync("Medications", "",
                                               "Storing Medications", 1000000)
        try {
            db.transaction(function (tx) {
                tx.executeSql(
                            'CREATE TABLE IF NOT EXISTS TablePatients (patientField TEXT)')
            })
        } catch (err6) {
            console.log("Error creating TablePatients in database: " + err6)
        }
        ;
    
        try {
            db.transaction(function (tx) {
                tx.executeSql(
                            'CREATE TABLE IF NOT EXISTS MedNamesTable (MednameField TEXT)')
            })
        } catch (err7) {
            console.log("Error creating MedNamesTable in database: " + err7)
        }
        ;
    }
    
    //Opening db
    function dbGetHandle() {
        dbInit()
        try {
            var db = LocalStorage.openDatabaseSync("Medications", "",
                                                   "Storing Medications", 1000000)
        } catch (err4) {
            console.log("Error opening database: " + err4)
        }
        return db
    }
    
    //Insert data into the TablePatients in the db
    function dbInsertPatients(newPatient) {
        dbGetHandle()
        console.log("newItem in Code.js: ", newPatient)
        console.log("TablePatients currentText in Code.js: ", newPatient)
        var db = dbGetHandle()
    
        db.transaction(function (tx) {
            tx.executeSql('INSERT OR IGNORE INTO TablePatients VALUES (?)',
                          [newPatient])
        })
    }
    
    //Read TablePatients from db
    function dbGetPatients() {
        var db = dbGetHandle()
        db.transaction(function (tx) {
            var results = tx.executeSql(
                        "SELECT patientField FROM TablePatients order by patientField asc")
            for (var i = 0; i < results.rows.length; i++) {
                listModel.append({
                                     "patientField": results.rows.item(
                                                         i).patientField,
                                     "checked": ""
                                 })
            }
        })
    }
    
    //Insert data into the MedNamesTable in the db
    function dbInsertMeds(newMed) {
        dbGetHandle()
        console.log("newMed in Code.js: ", newMed)
        console.log("MedNamesTable currentText in Code.js: ", newMed)
        var db = dbGetHandle()
    
        db.transaction(function (tx) {
            tx.executeSql('INSERT OR IGNORE INTO MedNamesTable VALUES (?)',
                          [newMed])
        })
    }
    

    When I use only 1 ComboBox on the page it works OK. When I have 2 I keep getting the following error message:
    Unable to assign [undefined] to QString on line
    text: model.MednameField //This is not working.

    text: model.MednameField //This is not working.
    
    

    How can I fix this? Thank you for your help.

    1 Reply Last reply
    0
    • sierdzioS Offline
      sierdzioS Offline
      sierdzio
      Moderators
      wrote on last edited by
      #2

      Are you really using 2 different models? Your code has model: ListModel in both cases, indicating that the models are 2 instances of the same class.

      (Z(:^

      G 1 Reply Last reply
      0
      • sierdzioS sierdzio

        Are you really using 2 different models? Your code has model: ListModel in both cases, indicating that the models are 2 instances of the same class.

        G Offline
        G Offline
        gabor53
        wrote on last edited by gabor53
        #3

        @sierdzio
        I need to access 2 different tables in the same db. Should I use like patientModel instead of listModel in the second ComboBox like

        model: patientModel {
        id: listPatient
        }
        

        ?
        Thank you for your help.

        1 Reply Last reply
        0
        • sierdzioS Offline
          sierdzioS Offline
          sierdzio
          Moderators
          wrote on last edited by
          #4

          I have no idea what your ListModel or PatientModel classes do, so I can't answer that.

          But if these 2 combo boxes need to display different data, then you definitely need 2 different models. Or at least 2 different instances of the same model with some different flags set so that they will know to serve different data.

          (Z(:^

          G 1 Reply Last reply
          0
          • sierdzioS sierdzio

            I have no idea what your ListModel or PatientModel classes do, so I can't answer that.

            But if these 2 combo boxes need to display different data, then you definitely need 2 different models. Or at least 2 different instances of the same model with some different flags set so that they will know to serve different data.

            G Offline
            G Offline
            gabor53
            wrote on last edited by gabor53
            #5

            @sierdzio
            Would you please show me an example how to create 2 different instances of the same ListModel to serve data from 2 different tables from the same database. I tried to give them different ids but, that clearly doesn't work.
            Thank you.

            1 Reply Last reply
            0
            • sierdzioS Offline
              sierdzioS Offline
              sierdzio
              Moderators
              wrote on last edited by
              #6

              @gabor53 said in Using 2 different ListModels with 2 different ComboBoxes:

              ListModel

              Wait wait wait, you are using stock ListModel? That is a static model, it does not connect to any database whatsoever.

              What you need is some subclass of QSqlQueryModel or QSqlTableModel (or custom QAbstractItemModel if you dare), set it up so that it gets correct data from DB, then expose it to QML and then it will work.

              Something like:

              class QueryModel: public QSqlQueryModel
              {
                  Q_OBJECT
              public:
                  explicit QueryModel(QObject *parent = nullptr) : QSqlQueryModel(parent)
                {
                  setQuery("SELECT someColumn FROM SomeTable", QSqlDatabase::database("my_db"));
                }
              };
              
              //...
              qmlEngine->rootContext()->setContextProperty("myQueryModel", queryModel);
              
              // QML
              model: myQueryModel
              
              

              (Z(:^

              G 1 Reply Last reply
              0
              • sierdzioS sierdzio

                @gabor53 said in Using 2 different ListModels with 2 different ComboBoxes:

                ListModel

                Wait wait wait, you are using stock ListModel? That is a static model, it does not connect to any database whatsoever.

                What you need is some subclass of QSqlQueryModel or QSqlTableModel (or custom QAbstractItemModel if you dare), set it up so that it gets correct data from DB, then expose it to QML and then it will work.

                Something like:

                class QueryModel: public QSqlQueryModel
                {
                    Q_OBJECT
                public:
                    explicit QueryModel(QObject *parent = nullptr) : QSqlQueryModel(parent)
                  {
                    setQuery("SELECT someColumn FROM SomeTable", QSqlDatabase::database("my_db"));
                  }
                };
                
                //...
                qmlEngine->rootContext()->setContextProperty("myQueryModel", queryModel);
                
                // QML
                model: myQueryModel
                
                
                G Offline
                G Offline
                gabor53
                wrote on last edited by
                #7

                @sierdzio
                I used this to connect the db to the model:

                //Read data from MedNamesTable
                function dbGetMeds() {
                    console.log("Entered dbGetMeds.")
                    var db = dbGetHandle()
                    db.transaction(function (tx) {
                        var results = tx.executeSql(
                                    "SELECT MednameField FROM MedNamesTable order by MednameField asc")
                        for (var i = 0; i < results.rows.length; i++) {
                            listModel2.append({
                                                  "MednameField": results.rows.item(
                                                                      i).MednameField,
                                                  "checked": ""
                                              })
                        }
                    })
                }
                

                It works in the first ComboBox but not in the second.

                1 Reply Last reply
                0
                • sierdzioS Offline
                  sierdzioS Offline
                  sierdzio
                  Moderators
                  wrote on last edited by
                  #8

                  Ah ok that makes it clear.

                  The reason why it does not work is that you only modify listModel or listModel2 in your DB functions. If you want the data to be present in both objects, you need to modify both of them, so something like:

                  let obj = {
                    "MednameField": results.rows.item(i).MednameField,
                    "checked": ""
                  }
                  
                  listModel.append(obj)
                  listModel2.append(obj)
                  

                  I still would say it's better to use the c++ classes for this purpose, though. Hacking ListModel seems like a temporary solution at best.

                  (Z(:^

                  G 2 Replies Last reply
                  1
                  • sierdzioS sierdzio

                    Ah ok that makes it clear.

                    The reason why it does not work is that you only modify listModel or listModel2 in your DB functions. If you want the data to be present in both objects, you need to modify both of them, so something like:

                    let obj = {
                      "MednameField": results.rows.item(i).MednameField,
                      "checked": ""
                    }
                    
                    listModel.append(obj)
                    listModel2.append(obj)
                    

                    I still would say it's better to use the c++ classes for this purpose, though. Hacking ListModel seems like a temporary solution at best.

                    G Offline
                    G Offline
                    gabor53
                    wrote on last edited by
                    #9

                    @sierdzio
                    No I understand. Thank you for your help.

                    1 Reply Last reply
                    0
                    • sierdzioS sierdzio

                      Ah ok that makes it clear.

                      The reason why it does not work is that you only modify listModel or listModel2 in your DB functions. If you want the data to be present in both objects, you need to modify both of them, so something like:

                      let obj = {
                        "MednameField": results.rows.item(i).MednameField,
                        "checked": ""
                      }
                      
                      listModel.append(obj)
                      listModel2.append(obj)
                      

                      I still would say it's better to use the c++ classes for this purpose, though. Hacking ListModel seems like a temporary solution at best.

                      G Offline
                      G Offline
                      gabor53
                      wrote on last edited by gabor53
                      #10

                      @sierdzio
                      I made the following changes:

                      function dbGetMeds() {
                          console.log("Entered dbGetMeds.")
                          var db = dbGetHandle()
                          db.transaction(function (tx) {
                              var results = tx.executeSql(
                                          "SELECT MednameField FROM MedNamesTable order by MednameField asc")
                              for (var i = 0; i < results.rows.length; i++) {
                                  let obj = {
                                      "MednameField": results.rows.item(i).MednameField,
                                      "checked": ""
                                  }
                              }
                          })
                      }
                      
                      model: ListModel{
                                      id: medModel
                                  }
                      Text {
                                          id: meds
                                          text: medModel.append(obj)
                                          font.pixelSize: 18
                                          color: Setup.delegateText()
                                          anchors.verticalCenter: parent.verticalCenter
                                      }
                      

                      I get no error message at all but there is nothing in the medCombo dropdown either. Am I still missing something?
                      Thank you.

                      sierdzioS 1 Reply Last reply
                      0
                      • G gabor53

                        @sierdzio
                        I made the following changes:

                        function dbGetMeds() {
                            console.log("Entered dbGetMeds.")
                            var db = dbGetHandle()
                            db.transaction(function (tx) {
                                var results = tx.executeSql(
                                            "SELECT MednameField FROM MedNamesTable order by MednameField asc")
                                for (var i = 0; i < results.rows.length; i++) {
                                    let obj = {
                                        "MednameField": results.rows.item(i).MednameField,
                                        "checked": ""
                                    }
                                }
                            })
                        }
                        
                        model: ListModel{
                                        id: medModel
                                    }
                        Text {
                                            id: meds
                                            text: medModel.append(obj)
                                            font.pixelSize: 18
                                            color: Setup.delegateText()
                                            anchors.verticalCenter: parent.verticalCenter
                                        }
                        

                        I get no error message at all but there is nothing in the medCombo dropdown either. Am I still missing something?
                        Thank you.

                        sierdzioS Offline
                        sierdzioS Offline
                        sierdzio
                        Moderators
                        wrote on last edited by
                        #11

                        @gabor53 said in Using 2 different ListModels with 2 different ComboBoxes:

                        Am I still missing something?

                        Yes, you are not modifying the model at all now (it is empty). You need to keep those append() calls in your loop!

                         for (var i = 0; i < results.rows.length; i++) {
                                    let obj = {
                                        "MednameField": results.rows.item(i).MednameField,
                                        "checked": ""
                                    }
                                    medModel.append(obj) // HERE!
                                }
                        

                        (Z(:^

                        G 1 Reply Last reply
                        1
                        • sierdzioS sierdzio

                          @gabor53 said in Using 2 different ListModels with 2 different ComboBoxes:

                          Am I still missing something?

                          Yes, you are not modifying the model at all now (it is empty). You need to keep those append() calls in your loop!

                           for (var i = 0; i < results.rows.length; i++) {
                                      let obj = {
                                          "MednameField": results.rows.item(i).MednameField,
                                          "checked": ""
                                      }
                                      medModel.append(obj) // HERE!
                                  }
                          
                          G Offline
                          G Offline
                          gabor53
                          wrote on last edited by
                          #12

                          @sierdzio
                          I made the new modifications like this:

                          //Read data from MedNamesTable
                          function dbGetMeds() {
                              console.log("Entered dbGetMeds.")
                              var db = dbGetHandle()
                              db.transaction(function (tx) {
                                  var results = tx.executeSql(
                                              "SELECT MednameField FROM MedNamesTable order by MednameField asc")
                                  for (var i = 0; i < results.rows.length; i++) {
                                      let obj = {
                                          "MednameField": results.rows.item(i).MednameField,
                                          "checked": ""
                                      }
                                      medModel.append(obj)
                                  }
                              })
                          }
                          
                          delegate: QQuick2.ItemDelegate {
                                          width: medCombo.width
                                          height: medCombo.height
                          
                                          //Defining the items in the dropdown list
                                          Text {
                                              id: meds
                                              text: medModel.MednameField
                                              font.pixelSize: 18
                                              color: Setup.delegateText()
                                              anchors.verticalCenter: parent.verticalCenter
                                          }
                                          onClicked: medCombo.currentIndex = index
                                          highlighted: medCombo.highlightedIndex === index
                                      }
                          
                          

                          Now it pulls the first item from the MedNamesTable and nothing else. Is

                           text: medModel.MednameField
                          

                          incorrect or something else? Thank you for your help.

                          1 Reply Last reply
                          0
                          • sierdzioS Offline
                            sierdzioS Offline
                            sierdzio
                            Moderators
                            wrote on last edited by
                            #13

                            Try calling it with lowercase first letter mednameField. QML engine might scoff at a property beginning with capital letter.

                            Code looks OK so if it displays just one entry - maybe there is only one row in your SQL table?

                            (Z(:^

                            G 1 Reply Last reply
                            0
                            • sierdzioS sierdzio

                              Try calling it with lowercase first letter mednameField. QML engine might scoff at a property beginning with capital letter.

                              Code looks OK so if it displays just one entry - maybe there is only one row in your SQL table?

                              G Offline
                              G Offline
                              gabor53
                              wrote on last edited by
                              #14

                              @sierdzio
                              Same problem. Regardless whether it is MednameField or mednameField it only pulls the last item from the db. I applied it to the patient combobox too with the same results. Even if I delete the

                              text: medModel.MednameField
                              

                              I get the same results. I am really puzzled now...

                              1 Reply Last reply
                              0

                              • Login

                              • Login or register to search.
                              • First post
                                Last post
                              0
                              • Categories
                              • Recent
                              • Tags
                              • Popular
                              • Users
                              • Groups
                              • Search
                              • Get Qt Extensions
                              • Unsolved