Skip to content

Instantly share code, notes, and snippets.

@estan
Last active February 11, 2016 20:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save estan/c051d1f798c4c46caa7d to your computer and use it in GitHub Desktop.
Save estan/c051d1f798c4c46caa7d to your computer and use it in GitHub Desktop.
Fixed experimentation with custom delegate + editor
from functools import partial
from sys import argv, exit
from PyQt5.QtCore import (Qt, QAbstractTableModel, QModelIndex, pyqtProperty,
pyqtSignal, QVariant)
from PyQt5.QtWidgets import (QApplication, QFrame, QStyledItemDelegate, QTableView,
QFormLayout, QSlider)
class MyAbstractItem(object):
def data(self, role):
raise NotImplementedError
def setData(self, value, role):
raise NotImplementedError
class MyTextItem(MyAbstractItem):
def __init__(self, text):
self._text = text
def data(self, role):
if role != Qt.DisplayRole and role != Qt.EditRole:
return None
return self._text
def setData(self, text, role):
if role != Qt.EditRole:
return False
self._text = text
return True
class MyCoolItem(MyAbstractItem):
def __init__(self, values):
self._values = values #: dict: Maps names to values
def data(self, role):
if role == Qt.DisplayRole:
return str(self._values) # Just as string for now.
elif role == Qt.EditRole:
return self._values
return None
def setData(self, values, role):
if role != Qt.EditRole:
return False
self._values = values
return True
class MyCoolEditor(QFrame):
def __init__(self, parent=None):
super(MyCoolEditor, self).__init__(parent)
self._values = None
self.setAutoFillBackground(True)
self.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
self.setLayout(QFormLayout())
@pyqtProperty(QVariant, user=True)
def values(self):
return self._values
@values.setter
def values(self, values):
self._values = values
while self.layout().count() > 0:
self.layout().takeAt(0)
for name, value in values.items():
slider = QSlider(Qt.Horizontal)
slider.setMinimum(0)
slider.setMaximum(100)
slider.setValue(value)
slider.valueChanged.connect(partial(self._setValue, name))
self.layout().addRow(name + ':', slider)
def _setValue(self, name, value):
self._values[name] = value
class MyCoolDelegate(QStyledItemDelegate):
def createEditor(self, parent, option, index):
values = index.data(Qt.EditRole)
if isinstance(values, dict):
return MyCoolEditor(parent)
return super(MyCoolDelegate, self).createEditor(parent, option, index)
def updateEditorGeometry(self, editor, option, index):
editor.setGeometry(option.rect.x(),
option.rect.y() + option.rect.height(), 200, 60)
class MyModel(QAbstractTableModel):
def __init__(self, headers, rows, parent=None):
super(MyModel, self).__init__(parent)
self._headers = headers
self._rows = rows
def rowCount(self, parent=QModelIndex()):
if parent.isValid():
return 0
return len(self._rows)
def columnCount(self, parent=QModelIndex()):
return len(self._headers)
def headerData(self, section, orientation, role=Qt.DisplayRole):
if orientation != Qt.Horizontal or role != Qt.DisplayRole:
return None
return self._headers[section]
def data(self, index, role=Qt.DisplayRole):
if not index.isValid():
return None
# Delegate to the item at the given index.
return self._rows[index.row()][index.column()].data(role)
def setData(self, index, value, role=Qt.EditRole):
if not index.isValid():
return False
# Delegate to the item at the given index.
if self._rows[index.row()][index.column()].setData(value, role):
self.dataChanged.emit(index, index)
return True
return False
def flags(self, index):
if not index.isValid():
return Qt.NoItemFlags
return Qt.ItemIsEditable | Qt.ItemIsEnabled | Qt.ItemIsSelectable
app = None
def main():
global app
app = QApplication(argv)
model = MyModel(
headers=['Cool Column', 'Text Column', 'Text Column'],
rows=[
[MyCoolItem({'a': 10, 'b': 20}), MyTextItem('c'), MyTextItem('c')],
[MyCoolItem({'d': 30, 'e': 50}), MyTextItem('f'), MyTextItem('c')],
[MyCoolItem({'d': 30, 'e': 50}), MyTextItem('f'), MyTextItem('c')],
[MyCoolItem({'d': 30, 'e': 50}), MyTextItem('f'), MyTextItem('c')],
[MyCoolItem({'d': 30, 'e': 50}), MyTextItem('f'), MyTextItem('c')]
],
parent=app
)
delegate = MyCoolDelegate(model)
view = QTableView()
view.setItemDelegateForColumn(0, delegate)
view.setModel(model)
view.show()
exit(app.exec_())
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment