I am trying to use a custom delegate to popup custom date and time editors for use inside of a qtreeview. Everything I read says that to get the editor widget to show up in the correct spot, over the current index, you reimpliment the updateEditorGeometry method and use editor.setGeometry(option.rect) to set the position.
I cannot seem to figure this out though. Here is what I have so far. When double clicking on column 1 it shows the editor in the very top left of my screen.
from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5.QtCore import Qt
import datetime
class NspDateEdit(QtWidgets.QWidget):
editingFinished = QtCore.pyqtSignal()
def __init__(self, parent=None):
super(NspDateEdit, self).__init__(parent)
# self.resize(137, 25)
# self.setMaximumSize(QtCore.QSize(120, 25))
self.date_edit = QtWidgets.QDateEdit()
self.date_edit.setCalendarPopup(True)
self.check_box = QtWidgets.QCheckBox()
self.check_box.setText("")
self.main_layout = QtWidgets.QHBoxLayout()
self.main_layout.addWidget(self.date_edit)
self.main_layout.addWidget(self.check_box)
self.main_layout.setContentsMargins(2, 0, 0, 0)
self.setLayout(self.main_layout)
self.check_box.stateChanged.connect(self._on_state_change)
self.date_edit.editingFinished.connect(self._on_editingFinished)
self.setDate(None)
def _on_state_change(self):
state = self.checkState()
if state:
current_date = self.date_edit.date()
current_date_py = current_date.toPyDate()
current_date_str = current_date_py.strftime('%Y-%m-%d')
if current_date_str == '2000-01-01':
new_date = datetime.datetime.now().date()
else:
new_date = current_date_py
self.setDate(new_date)
else:
self.setDate(None)
self.editingFinished.emit()
def _on_editingFinished(self):
self.editingFinished.emit()
def checkState(self):
state = self.check_box.checkState()
if state == Qt.Checked:
return True
else:
return False
def setDate(self, val):
self.date_edit.setEnabled(True)
if val is None:
self.check_box.setCheckState(Qt.Unchecked)
self.date_edit.setEnabled(False)
else:
self.date_edit.setDate(val)
self.check_box.setCheckState(Qt.Checked)
def date(self):
if self.checkState():
return self.date_edit.date().toPyDate()
else:
return None
class NspAbstractItemDelegate(QtWidgets.QStyledItemDelegate):
def __init__(self):
super(NspAbstractItemDelegate, self).__init__()
def createEditor(self, parent, option, index):
editor = NspDateEdit()
editor.setWindowFlags(QtCore.Qt.Popup)
return editor
def setEditorData(self, editor, index):
data = index.data()
formatted = datetime.datetime.strptime(data, '%m/%d/%y').date()
editor.setDate(formatted)
def setModelData(self, editor, model, index):
data = editor.date()
txt = data.strftime('%m/%d/%y')
model.setData(index, txt)
def updateEditorGeometry(self, editor, option, index):
editor.setGeometry(option.rect)
class testTreeview(QtWidgets.QWidget):
def __init__(self, parent=None):
super(testTreeview, self).__init__(parent)
self.mainTree = QtWidgets.QTreeView()
self.testButton = QtWidgets.QPushButton()
self.lo = QtWidgets.QVBoxLayout()
self.lo.addWidget(self.mainTree)
self.lo.addWidget(self.testButton)
self.setLayout(self.lo)
self.model = QtGui.QStandardItemModel()
self.mainTree.setModel(self.model)
self.populate()
self.testButton.clicked.connect(self._on_clicked_button)
self.mainTree.setItemDelegateForColumn(0, NspAbstractItemDelegate())
def _on_clicked_button(self):
self.mainTree.edit(self.mainTree.currentIndex()) #, QtWidgets.QAbstractItemView.EditTrigger(), None)
def populate(self):
row = [QtGui.QStandardItem('05/12/15'), QtGui.QStandardItem('07/13/18'), ]
row2 = [QtGui.QStandardItem('12/21/21'), QtGui.QStandardItem('11/05/17'), ]
all_rows = list(row)
all_rows.extend(row2)
for item in all_rows:
item.setEditable(True)
root = self.model.invisibleRootItem()
root.appendRow(row)
root.appendRow(row2)
if __name__ == "__main__":
from PyQt5 import QtCore, QtGui, QtWidgets
app = QtWidgets.QApplication([])
volume = testTreeview()
volume.show()
app.exec_()