[PyQt] problem with setItemDelegateForColumn and
ItemIsUserCheckable
Brian DeWeese
brian.deweese at gmail.com
Wed Jun 6 16:00:10 BST 2007
David,
Thanks for your reply. I was passing a QObject (a QDialog to be exact) as
the parent to the delegate but I wasn't storing a reference to the delegate
anywhere so perhaps it was being deleted in some cases. I added a variable
to store the reference to the delegate but unfortunately that didn't change
anything. I pared down the code to it's bare minimum and included it here.
Thanks for looking into the problem.
Brian DeWeese
<code start of BugTest.py>
#!/usr/bin/env python
import sys
from PyQt4 import QtGui, QtCore
_qvChecked = QtCore.QVariant(QtCore.Qt.Checked)
_qvUnchecked = QtCore.QVariant(QtCore.Qt.Unchecked)
##------------------------------------------------------------------------------
class BTObject(object):
def __init__(self, enabled=False, foo='', bar=0):
object.__init__(self)
self._enabled = enabled
self._foo = foo
self._bar = bar
def isEnabled(self):
return self._enabled
def setEnabled(self, b=True):
self._enabled = b
def createInlineEditor(self, parent):
return BTObject.InlineEditor(self, parent)
def __repr__(self):
return 'BTObject(enabled='+str(self._enabled)+',
foo=\"'+str(self._foo)+'\", bar='+str(self._bar)+')'
class InlineEditor(QtGui.QWidget):
_MUTE = 'MUTE'
def __init__(self, btobject, parent):
QtGui.QWidget.__init__(self, parent)
self._btobject = btobject
self.setAutoFillBackground(True)
lo = QtGui.QHBoxLayout()
lo.setMargin(0)
lo.setSpacing(4)
self._cbFoo = QtGui.QComboBox()
for x in ["ABC", "DEF", "GHI", "JKL"]:
self._cbFoo.addItem(x)
self._leBar = QtGui.QLineEdit(str(btobject._bar), self)
self._leBar.setValidator(QtGui.QIntValidator(0, 999999, self))
lo.addWidget(self._cbFoo, 3)
lo.addSpacing(5)
lo.addWidget(QtGui.QLabel('Bar:'))
lo.addWidget(self._leBar, 3)
lo.addStretch(5)
self.setLayout(lo)
# set the object data into the gui
self._cbFoo.setCurrentIndex(self._cbFoo.findText(self._btobject._foo))
self._leBar.setText(str(self._btobject._bar))
def accept(self):
text = str(self._cbFoo.currentText())
self._btobject._foo = text
self._btobject._bar = int(self._leBar.text())
print 'accept: btobject='+repr(self._btobject)
def reject(self):
pass
##>--------------------------------------------------------------------------<##
class BTModel(QtCore.QAbstractTableModel):
def __init__(self, parent=None ):
QtCore.QAbstractTableModel.__init__(self, parent)
self._items = [BTObject(foo="ABC", bar=1),
BTObject(foo="DEF", bar=2),
BTObject(foo="GHI", bar=3)]
self._headerData = (QtCore.QVariant("Name"), QtCore.QVariant
("repr"))
def columnCount(self, parentIndex):
return len(self._headerData)
def flags(self, index):
if not index.isValid():
return QtCore.Qt.ItemIsEnabled
if index.column() == 0:
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable |
QtCore.Qt.ItemIsUserCheckable
elif index.column() == 1:
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable |
QtCore.Qt.ItemIsEditable
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
def getItemAt(self, row):
if row >= 0 and row < len(self._items):
return self._items[row]
return None
def indexOfItem(self, item):
return self._items.index(item)
def headerData(self, section, orientation, role):
if orientation == QtCore.Qt.Horizontal and role in (
QtCore.Qt.DisplayRole, QtCore.Qt.EditRole):
return self._headerData[section]
return QtCore.QVariant()
def rowCount(self, parentIndex):
return len(self._items)
def setData(self, index, value, role):
if index.isValid():
if index.column() == 0 and role == QtCore.Qt.CheckStateRole:
state = value.toInt()[0] # int value stored as a tuple,
where's that documented?
btobject = self._items[index.row()]
btobject.setEnabled(state == QtCore.Qt.Checked)
# Force a repaint of the entire row.
index2 = self.createIndex(index.row(), 1)
self.emit(QtCore.SIGNAL('dataChanged(const QModelIndex &,
const QModelIndex &)'), index2, index2)
return True
def data( self, index, role ):
if not index.isValid():
return QtCore.QVariant()
if role == QtCore.Qt.DisplayRole:
col = index.column()
if col == 0:
return QtCore.QVariant(self._items[index.row()]._foo)
elif col == 1:
return QtCore.QVariant(repr(self._items[index.row()]))
elif role == QtCore.Qt.CheckStateRole:
if index.column() == 0:
retVal = _qvUnchecked
btobject = self._items[index.row()]
if btobject.isEnabled():
retVal = _qvChecked
return retVal
return QtCore.QVariant()
##>--------------------------------------------------------------------------<##
class BTItemDelegate(QtGui.QItemDelegate):
def __init__(self, parent):
QtGui.QItemDelegate.__init__(self, parent)
def createEditor(self, parent, option, index):
if index.column() == 1:
model = index.model()
btobject = model.getItemAt(index.row())
editor = btobject.createInlineEditor(parent)
return editor
return QtGui.QItemDelegate.createEditor(self, parent, option, index)
def setEditorData(self, editor, index):
''' I don't need to do anything here because I passed in the object
being edited when the editor was constructed.
'''
pass
def setModelData(self, editor, model, index):
editor.accept()
##>--------------------------------------------------------------------------<##
class BTEditor(QtGui.QDialog):
def __init__(self, parent=None):
QtGui.QDialog.__init__(self, parent)
self.setWindowTitle('BTObject Editor')
# Create a button box for the dialog containing the Ok and Cancel
buttons
buttonBox = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok
| QtGui.QDialogButtonBox.Cancel);
QtCore.QObject.connect(buttonBox, QtCore.SIGNAL('accepted()'),
self.accept)
QtCore.QObject.connect(buttonBox, QtCore.SIGNAL('rejected()'),
self.reject)
# The tree view widget
self._view = BTEditor.TableView(self)
self._view.setMinimumSize(QtCore.QSize(300, 100))
self._delegate = BTItemDelegate(self)
#----------------------------------------------------------------------#
# If you comment out the setItemDelegat calls than the checkable
# column will work correctly. If setItemDelegate is uncommented
# than the custom editor will work but it breaks the checkable
# column. If setItemDelegateForColumn is uncommented than the
# checkable column works correctly but my editor is never used
# either.
#----------------------------------------------------------------------#
self._view.setItemDelegate(self._delegate)
#self._view.setItemDelegateForColumn(1, self._delegate) # this
doesn't work
self._model = BTModel()
self._view.setModel(self._model)
# The final layout, putting it all together
gl = QtGui.QGridLayout()
gl.addWidget(self._view , 1, 0, 1, 2)
gl.addWidget(buttonBox , 2, 0, 1, 2)
self.setLayout(gl)
##------------------------------------------------------------------------##
class TableView(QtGui.QTableView):
def __init__(self, parent):
QtGui.QTableView.__init__(self, parent)
self.verticalHeader().hide()
self.setAlternatingRowColors(True)
self.setEditTriggers(QtGui.QAbstractItemView.DoubleClicked |
QtGui.QAbstractItemView.EditKeyPressed)
self.setGridStyle(QtCore.Qt.NoPen)
self.setLineWidth(0)
self.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
self.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
self.horizontalHeader().setStretchLastSection(True)
self.horizontalHeader().setResizeMode(
QtGui.QHeaderView.ResizeToContents )
self.verticalHeader().setResizeMode(
QtGui.QHeaderView.ResizeToContents )
def sizeHint(self):
return QtCore.QSize(600, 100)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
win = BTEditor()
win.show()
app.connect(app, QtCore.SIGNAL('lastWindowClosed()'), app, QtCore.SLOT
('quit()'))
sys.exit(app.exec_())
</code>
Brian DeWeese
On 6/5/07, David Boddie <david at boddie.org.uk> wrote:
>
> On Fri, 1 Jun 2007 09:56:25 -0500, Brian DeWeese wrote:
>
> > I have a 2 column QTableView where column 0 is checkable and column 1 is
> > editable. I've written a custom editor by implement QItemDelegate which
> is
> > working fine. Also, the checkbox in column 0 is also working fine. But
> > not both at the same time.
> >
> > If I use view.setItemDelegate(myDelegate) than my delegate is called to
> > create my custom editor and everything about column 1 works correctly.
> But
> > column 0 doesn't work correctly. It is displaying a checkbox with the
> > correct current value but clicking on it does not call my model's
> setData()
> > method or do anything at all as far as I can tell.
>
> OK. This doesn't sound right.
>
> > If I use view.setItemDelegateForColumn(1, myDelegate) than the checkbox
> in
> > colum 0 works but double-clicking on column 1 will ignore my delegate
> and
> > create a default editor.
>
> Did you create the delegate in a way that stops it from being garbage
> collected and subsequently deleted on the C++ side? In other words,
> did you store the instance somewhere, or create it with a parent QObject?
>
> I'm guessing that you did, otherwise you wouldn't see your editor in the
> previous situation. :-/
>
> > Is this a known bug in either PyQt or Qt itself? Or am I doing something
> > wrong?
>
> I would like to see more code before declaring something wrong with
> setItemDelegateForColumn() in either Qt or PyQt.
>
> > I'm using PyQt 4.1.1 with Qt 4.2 on SUSE 10.1. (BTW, Is there a proper
> way
> > to verify that I'm using the versions that I think I'm using?)
>
> from PyQt4 import pyqtconfig
> hex(pyqtconfig._pkg_config["pyqt_version"])
> hex(pyqtconfig._pkg_config["qt_version"])
>
> > Here is my model.flags() method.
> >
> > def flags(self, index):
> > if not index.isValid():
> > return QtCore.Qt.ItemIsEnabled
> >
> > if index.column() == 0:
> > return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable |
> > QtCore.Qt.ItemIsUserCheckable
>
> You might want to make this editable, too.
>
> > elif index.column() == 1:
> > return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable |
> > QtCore.Qt.ItemIsEditable
> >
> > return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
>
> Hope this helps,
>
> David
>
> _______________________________________________
> PyQt mailing list PyQt at riverbankcomputing.com
> http://www.riverbankcomputing.com/mailman/listinfo/pyqt
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.riverbankcomputing.com/pipermail/pyqt/attachments/20070606/7891d732/attachment-0001.html
More information about the PyQt
mailing list