Reputation: 45
The code is supposed to get the number of rows in the table of the database and use it as the number of models and also display all rows on the ListView after the btnShowList is clicked However, Nothing occurs upon clicking. There are two files.
main.qml
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
property var numberOfModels: 1
property var listofCust: []
Rectangle{
id: listViewContainer
color: "pink"
anchors.fill: parent
ListModel {
id: displayCustomers
ListElement{
firstName: "First Name"
LastName: "Last Name"
age: "Age"
Sex: "Sex"
}
}
Component{
id:customersDelegate
Row{
spacing: 50
Text{
text: firstName
}
Text {
text: LastName
}
Text {
text: age
}
Text {
text: Sex
}
}
}
ListView{
anchors.fill: parent
anchors.bottomMargin: 52
model: displayCustomers
delegate: customersDelegate
}
Button {
id: btnShowList
x: 518
y: 440
text: qsTr("show list")
onClicked: {
displayCustomers.append(backend.getCount)
}
}
}
Connections {
target: backend
function onGetCount(total, listofCust){
count = total
numberOfModels = total
listofCus = listofCust
return listofCust
}
}
}
main.py
import sys
import os
import mysql.connector
from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine
from PySide2.QtCore import QObject, Slot, Signal
class MainWindow(QObject):
def __init__(self):
QObject.__init__(self)
count = Signal(int)
listOfCus = Signal([])
@Slot()
def getCount(self):
db = mysql.connector.connect(
host = "localhost",
user = "root",
passwd = "",
database = "test"
)
mycursor = db.cursor()
mycursor.execute("SELECT * FROM customer")
listofCustomers = []
total = 0
for x in mycursor:
total = total + 1
print(x)
listofCustomers.append(x)
self.count.emit(total)
print(total)
values = mycursor
print(values)
print(listofCustomers)
self.listOfCus.emit()
if __name__ == "__main__":
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
#Get Context
main = MainWindow()
engine.rootContext().setContextProperty("backend", main)
engine.load(os.path.join(os.path.dirname(__file__), "main.qml"))
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec_())
There is no error upon execution. When I print the listofCustomers and total i get the intended output. But the listView does not display anything after clicking the button
Upvotes: 0
Views: 2374
Reputation: 244301
The OP expects the database information to magically show up in the view without at least sending that information to .qml.
On the other hand the line "displayCustomers.append (backend.getCount)" is confusing, what do you intend to happen with that code? In that code the getCount function is being added to the model which is obviously illogical.
The idea is to have a model (in python or QML) that has the roles that are the same as those used by the delegate, the slot should only serve to fill the model, in this case I will use a python model.
import os
from pathlib import Path
import sys
import mysql.connector
from PySide2.QtCore import Property, QCoreApplication, QObject, Qt, QUrl, Slot
from PySide2.QtGui import QGuiApplication, QStandardItem, QStandardItemModel
from PySide2.QtQml import QQmlApplicationEngine
CURRENT_DIRECTORY = Path(__file__).resolve().parent
FIRSTNAME_ROLE = Qt.UserRole
LASTNAME_ROLE = Qt.UserRole + 1
AGE_ROLE = Qt.UserRole + 2
SEX_ROLE = Qt.UserRole + 3
class Backend(QObject):
def __init__(self, parent=None):
super().__init__(parent)
self._model = QStandardItemModel()
self._model.setItemRoleNames(
{
FIRSTNAME_ROLE: b"firstname",
LASTNAME_ROLE: b"lastname",
AGE_ROLE: b"age",
SEX_ROLE: b"sex",
}
)
self.add_row("Fistname", "LastName", "Age", "Sex")
def get_model(self):
return self._model
model = Property(QObject, fget=get_model, constant=True)
@Slot()
def loadFromDB(self):
self._model.clear()
db = mysql.connector.connect(
host="localhost", user="root", passwd="", database="test"
)
cursor = db.cursor()
cursor.execute("SELECT * FROM customer")
for row in cursor.fetchall():
firstname = row[0]
lastname = row[1]
age = row[2]
sex = row[3]
self.add_row(firstname, lastname, age, sex)
def add_row(self, firstname, lastname, age, sex):
item = QStandardItem()
item.setData(firstname, FIRSTNAME_ROLE)
item.setData(lastname, LASTNAME_ROLE)
item.setData(age, AGE_ROLE)
item.setData(sex, SEX_ROLE)
self._model.appendRow(item)
if __name__ == "__main__":
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
# Get Context
backend = Backend(app)
engine.rootContext().setContextProperty("backend", backend)
filename = os.fspath(CURRENT_DIRECTORY / "main.qml")
url = QUrl.fromLocalFile(filename)
def handle_object_created(obj, obj_url):
if obj is None and url == obj_url:
QCoreApplication.exit(-1)
engine.objectCreated.connect(handle_object_created, Qt.QueuedConnection)
engine.load(url)
sys.exit(app.exec_())
main.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Window 2.15
Window {
property var numberOfModels: 1
property var listofCust: []
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Rectangle {
id: listViewContainer
color: "pink"
anchors.fill: parent
Component {
id: customersDelegate
Row {
spacing: 50
Text {
text: firstname
}
Text {
text: lastname
}
Text {
text: age
}
Text {
text: sex
}
}
}
ListView {
anchors.fill: parent
anchors.bottomMargin: 52
model: backend.model
delegate: customersDelegate
}
Button {
id: btnShowList
x: 518
y: 440
text: qsTr("show list")
onClicked: {
backend.loadFromDB();
}
}
}
}
Upvotes: 3
Reputation: 8287
I think you've confused what a model and delegate are. Your model should contain WHAT data is to be displayed. Your delegate defines HOW that data is to be displayed. In your example, your delegate is not a visual item. It looks like it's retrieving data, which should go into the model. Here is an example of what it should look like:
ListView {
// The model is the data
model: [2,4,6,8]
// The delegate is the view
delegate: Text {
text: modelData
}
}
Upvotes: 1