ich versuche momentan Daten einer Sqlite-Datenbank über ein Model an eine View in QML weiterzugeben und dort anzeigen zu lassen. Problem dabei ist, dass es keine Modelklasse gibt, die beliebig viele Spalten einer Abfrage an QML liefert. Da ich aber ein Projekt anstrebe, was viele Abfragen beansprucht, habe ich eine eigene Klasse von QSqlQueryModel abgeleitet und erzeuge die Userroles automatisch beim Erstellen der Abfrage.
Die Oberfläche besteht im wesentlichen aus Listviews, die die Daten anzeigen. Beim Klicken auf ein Element wird in QML die Methode des Controllers aufgerufen update_model(model, keyword, value), wo halt das model, art der abfrage und der jeweilige Wert übergeben werden. Die neue Listview wird in einem neuen Pagestack angezeigt.
Das funktioniert auch soweit, allerdings verabschiedet sich das Programm manchmal mit einem Segmentation Fault und zwar eigentlich immer nur dann, wenn die Noten generiert werden. Ich konnte es soweit eingrenzen, dass der Aufruf super(SqlQueryModel,self).setQuery(query) in der von QSqlQueryModel abgeleiteten Klasse den Fehler auslöst. Das Problem ist auch reproduzierbar, also wenn ich z.B. die Klasse 08A auswähle, dort den ersten Schüler zurückgehe und dann den nächsten Schüler, bricht das Programm ab:
Code: Alles auswählen
Clicked on At
SELECT kurse.kursId as kursId, stufe, fach FROM kurse, lehrerunterrichtet WHERE lehrerunterrichtet.lehrerId=13 AND kurse.kursId = lehrerunterrichtet.kursId ORDER BY stufe, fach
Clicked on 464
SELECT s.schuelerId, vorname, nachname, substr(nachname,1,1) as alphabet FROM schueler s, kurswirdbesucht kwb WHERE s.schuelerId = kwb.schuelerId AND kursId=464 ORDER BY nachname
Clicked on 898
SELECT nachname, s.stufe, fach, note FROM schueler s, kurse k, kurswirdbesucht kwb WHERE kwb.schuelerId = s.schuelerId AND k.kursId = kwb.kursId AND s.schuelerId = 898
Clicked on 899
SELECT nachname, s.stufe, fach, note FROM schueler s, kurse k, kurswirdbesucht kwb WHERE kwb.schuelerId = s.schuelerId AND k.kursId = kwb.kursId AND s.schuelerId = 899
Segmentation fault
Was mache ich falsch bzw. wie kann ich das noch weiter debuggen?
Ein Minimalbeispiel mit meiner Modelklasse funktioniert ohne Fehler, leider kann ich die DB nicht posten, da sie sensible Daten enthält.
Wäre für jeden Hinweis dankbar!
Gruß EmaNymton
Code: Alles auswählen
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
from PySide import QtSql, QtGui, QtDeclarative, QtCore
querys = {
"stufen": 'SELECT DISTINCT stufe FROM kurse \
WHERE stufe!="" ORDER BY stufe',
"schueler_stufe" : 'SELECT schuelerId, vorname, nachname, \
substr(nachname,1,1) as alphabet \
FROM schueler \
WHERE stufe="{0}" \
ORDER BY nachname',
"schueler_kurs" : 'SELECT s.schuelerId, vorname, nachname, substr(nachname,1,1) as alphabet\
FROM schueler s, kurswirdbesucht kwb\
WHERE s.schuelerId = kwb.schuelerId\
AND kursId={0} ORDER BY nachname',
"noten" : 'SELECT nachname, s.stufe, fach, note\
FROM schueler s, kurse k, kurswirdbesucht kwb\
WHERE kwb.schuelerId = s.schuelerId\
AND k.kursId = kwb.kursId\
AND s.schuelerId = {0}',
"lehrer" : 'SELECT lehrerId, kuerzel FROM lehrer ORDER BY kuerzel',
"kurse" : 'SELECT kurse.kursId as kursId, stufe, fach\
FROM kurse, lehrerunterrichtet\
WHERE lehrerunterrichtet.lehrerId={0}\
AND kurse.kursId = lehrerunterrichtet.kursId\
ORDER BY stufe, fach'
}
class SqlQueryModel(QtSql.QSqlQueryModel):
def __init__(self, parent=None):
super(SqlQueryModel,self).__init__(parent)
def setQuery(self, query):
super(SqlQueryModel,self).setQuery(query)
self.generateRoleNames()
def generateRoleNames(self):
roleNames = super(SqlQueryModel,self).roleNames()
for i in range(self.record().count()):
roleNames[QtCore.Qt.UserRole + i + 1] = str(self.record().fieldName(i))
self.setRoleNames(roleNames)
def data(self, index, role = QtCore.Qt.DisplayRole):
if role < QtCore.Qt.UserRole:
value = super(SqlQueryModel,self).data(index, role)
else:
columnIdx = role - QtCore.Qt.UserRole - 1;
modelIndex = QtCore.QModelIndex(self.index(index.row(),
columnIdx))
value = super(SqlQueryModel,self).data(modelIndex,
QtCore.Qt.DisplayRole)
return value
class Controller(QtCore.QObject):
def __init__(self, querys):
QtCore.QObject.__init__(self)
self._querys = querys
self._last_query = None
@QtCore.Slot(QtCore.QObject, str, str)
def update_model(self, model, keyword, value):
query = self._querys[keyword].format(value)
print query
if self._last_query != query:
model.setQuery(query)
self._last_query = query
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName("noten.db")
if db.open():
stufen_model = SqlQueryModel()
schueler_model = SqlQueryModel()
noten_model = SqlQueryModel()
lehrer_model = SqlQueryModel()
kurse_model = SqlQueryModel()
stufen_model.setQuery(querys["stufen"])
schueler_model.setQuery(querys["schueler_stufe"].format('10X'))
noten_model.setQuery(querys["noten"].format('1'))
lehrer_model.setQuery(querys["lehrer"])
kurse_model.setQuery(querys["kurse"].format('1'))
controller = Controller(querys)
view = QtDeclarative.QDeclarativeView()
rc = view.rootContext()
rc.setContextProperty('controller', controller)
rc.setContextProperty('stufenModel', stufen_model)
rc.setContextProperty('schuelerModel', schueler_model)
rc.setContextProperty('notenModel', noten_model)
rc.setContextProperty('lehrerModel', lehrer_model)
rc.setContextProperty('kurseModel', kurse_model)
view.setSource("main.qml")
view.showFullScreen()
sys.exit(app.exec_())
else:
print "database not open, quit!"
sys.exit(1)