Unsolved Using 2 different ListModels with 2 different ComboBoxes
-
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.
-
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. -
@sierdzio
I need to access 2 different tables in the same db. Should I use like patientModel instead of listModel in the second ComboBox likemodel: patientModel { id: listPatient }
?
Thank you for your help. -
I have no idea what your
ListModel
orPatientModel
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.
-
@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. -
@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
-
@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.
-
Ah ok that makes it clear.
The reason why it does not work is that you only modify
listModel
orlistModel2
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.
-
@sierdzio
No I understand. Thank you for your help. -
@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. -
@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! }
-
@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.
-
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?
-
@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 thetext: medModel.MednameField
I get the same results. I am really puzzled now...