[PyKDE] Model-View application: view not updated
Sibylle Koczian
Sibylle.Koczian at T-Online.de
Sat Dec 16 14:19:00 GMT 2006
"Andreas Pakulat" <apaku at gmx.de> schrieb:
> On 15.12.06 16:17:21, Sibylle Koczian wrote:
> > The problem is with the cancel button: the changed records are only
> > changed back after the window lost focus - the view isn't updated
> > directly after clicking the button. It _is_ updated after changing the
> > spin box value - but only if it's a real change, not after changing and
> > changing back again to the old value. I can't understand this, because
> > in both cases the same method is called.
>
> Hmm, I don't think I follow your description.
I'll try again. The application is started and shows some records in a QTableView. I edit one or more of these records and decide to cancel my alterations. So I click on "cancel". No change in the view. Now I can do several things to get back the unedited records:
- I click into another window - _now_ the view changes to show the edited records in their original form.
- I choose another value in my spinbox and click on "ok" - the view shows a new set of records, as it should. Back to the first value: it shows the unedited records of the first set, again as it should.
- I try to trick my application by changing the spinbox value twice and clicking "ok" only after returning to the original value: no change, I see the edited records and not the original form.
All of this hasn't really anything to do with database use, the example script doesn't use any database at all.
BTW: Did you look at the
> ready-made models for accessing SQL databases in Qt4?
>
I did, but:
I didn't understand how to get the SQL support for Firebird. Especially using Ubuntu which doesn't put Firebird in the standard place Qt4 expects it in.
And I've already got a lot of functions using kinterbasdb with my database (all the work which can be done without a GUI). So I'm not so very happy with the thought of changing the database driver.
> > I've reduced the problem to a smaller application with a small global
> > list in place of the database - the offending behaviour stays the same.
> > But it's still 153 lines of code. Should I post it or is the description
> > sufficient?
>
> 153 loc is not really large, please post it.
>
Ok, here it is. Thanks to everybody taking a look!
Sibylle
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
view_update.py
Test update of view with editable model subclassed from QAbstractTableModel.
"""
import sys
from PyQt4 import QtCore, QtGui
gData = [[(101, 'Beckenbauer', 'Franz'), (102, 'Braun', 'Egidius'),
(103, 'Hackmann', 'Werner'), (104, 'Zwanziger', 'Theo')],
[(201, 'Doll', 'Thomas'), (202, 'Funkel', 'Friedhelm'),
(203, 'Hitzfeld', 'Otmar'), (204, 'Magath', 'Felix'),
(205, 'Veh', 'Armin')],
[(301, 'Huggel', 'Benjamin'), (302, 'Jones', 'Jermaine'),
(303, 'Spycher', 'Christoph')]]
cFelder = ['IDNr', 'LastName', 'FirstName']
class TestModel(QtCore.QAbstractTableModel):
def __init__(self, columnTitles, parent=None):
QtCore.QAbstractTableModel.__init__(self, parent)
self._resultRows = []
self._columnTitles = columnTitles
def columnCount(self, parent):
return len(self._columnTitles)
def rowCount(self, parent):
return len(self._resultRows)
def data(self, index, role):
if not (index.isValid() and role in (QtCore.Qt.DisplayRole,
QtCore.Qt.EditRole)):
return QtCore.QVariant()
value = self._resultRows[index.row()][index.column()]
if value is None:
value = ""
if isinstance(value, str):
try:
value = unicode(value, "UTF-8")
except UnicodeError:
value = unicode(value, "ISO-8859-1")
else:
value = unicode(value)
return QtCore.QVariant(value)
def headerData(self, section, orientation, role):
if role != QtCore.Qt.DisplayRole:
return QtCore.QVariant()
if orientation == QtCore.Qt.Horizontal:
return QtCore.QVariant(self._columnTitles[section])
elif orientation == QtCore.Qt.Vertical:
return QtCore.QVariant(section + 1)
return QtCore.QVariant()
def flags(self, index):
# First column (IDNr) may not be editable
flags = QtCore.QAbstractItemModel.flags(self, index)
if index.column() > 0:
flags |= QtCore.Qt.ItemIsEditable
return flags
def setData(self, index, value, role):
if index.column() > 0:
s = value.toString()
self._resultRows[index.row()][index.column()] = str(s)
else:
return False
self.emit(QtCore.SIGNAL('dataChanged(const QModelIndex &, '
'const QModelIndex &)'),
index, index)
return True
def setResultset(self, recno):
print "TestModel.setResultset called"
# The items in _resultRows can't be tuples if the model shall be
# editable
self._resultRows = [list(rec) for rec in gData[recno]]
self.reset()
def submitAll(self, recno):
print "TestModel.submitAll called"
gData[recno] = [tuple(rec) for rec in self._resultRows]
class TestView(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.model = TestModel(cFelder)
self.model.setResultset(1)
lb = QtGui.QLabel('&List No')
self.chooseRecord = QtGui.QSpinBox()
self.chooseRecord.setRange(0, len(gData) - 1)
self.chooseRecord.setValue(1)
lb.setBuddy(self.chooseRecord)
btOk = QtGui.QPushButton('ok')
self.view = QtGui.QTableView()
self.view.setModel(self.model)
self.view.setAlternatingRowColors(True)
btSubmit = QtGui.QPushButton('&Submit')
btCancel = QtGui.QPushButton('&Cancel')
mbox = QtGui.QVBoxLayout()
hbox = QtGui.QHBoxLayout()
hbox.addWidget(lb)
hbox.addWidget(self.chooseRecord)
hbox.addWidget(btOk)
mbox.addLayout(hbox)
mbox.addWidget(self.view)
hbox = QtGui.QHBoxLayout()
hbox.addWidget(btSubmit)
hbox.addWidget(btCancel)
mbox.addLayout(hbox)
self.setLayout(mbox)
self.resize(360, 300)
self.connect(btOk, QtCore.SIGNAL('clicked()'), self.fillTable)
self.connect(btCancel, QtCore.SIGNAL('clicked()'), self.fillTable)
self.connect(btSubmit, QtCore.SIGNAL('clicked()'), self.saveTable)
self.connect(self.model, QtCore.SIGNAL("modelReset()"),
self.resetModel)
def fillTable(self):
print "fillTable called"
self.model.setResultset(self.chooseRecord.value())
def saveTable(self):
print "saveTable called"
self.model.submitAll(self.chooseRecord.value())
def resetModel(self):
print "Signal modelReset empfangen"
self.view.update()
# This is called after clicking the "Submit" button, but the view _isn't_ updated.
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
test = TestView()
test.show()
sys.exit(app.exec_())
--
Dr. Sibylle Koczian
Fasanenstrasse 12
D-82293 Mittelstetten
More information about the PyQt
mailing list