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