Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

correctly manage sizeHint for item in delegate with custom editor



  • Hello,
    I have a listview with a delegate for a custom editor for managing the items custom data. I simplified this example so the editor for now is two line edits and a push button, so the editors height is bigger than the default items height.

    I've manage to get a 'sortof' working solution, but I think there is a better way to mange then sizeHint as i'm hard coding it and storing a items editing state on the item data.

    1. Is there a better way in the sizeHint to test if a item is currently being edited? I'm having to store a bool and manage that for each item.

    2. Is there a way to get an item's minimum size (the size when the listview first creates it), so I dont have to hard code it scale back down after editing.

    If there is a better way please let me know to manage a custom editors size. I saw the updateEditorGeometry function aswell, but wasn't sure i needed to implement that

    Cheers.

    
    import sys
    from collections import namedtuple
    from PySide2 import QtGui, QtCore, QtWidgets
    from PySide2.QtCore import Qt
    
    
    __custom_roles = dict(title = Qt.UserRole + 1, description = Qt.UserRole + 2, cur_state = Qt.UserRole + 3)
    CustomRoles = namedtuple('CustomRoles', __custom_roles.keys())(*__custom_roles.values())
    
    
    class Editor(QtWidgets.QWidget):
    
        editingFinished = QtCore.Signal()
    
        def __init__(self, parent=None):
            super(Editor, self).__init__(parent)
            print('EDITOR CREATED')
            self.title_edit_le = QtWidgets.QLineEdit()
            self.description_edit_le = QtWidgets.QLineEdit()
            self.close_editor_pb = QtWidgets.QPushButton('close editor')
            v_layout = QtWidgets.QVBoxLayout()
            v_layout.setContentsMargins(0,0,0,0)
            v_layout.addWidget(self.title_edit_le)
            v_layout.addWidget(self.description_edit_le)
            v_layout.addWidget(self.close_editor_pb)
            self.setLayout(v_layout)
            self.close_editor_pb.clicked.connect(self.editingFinished.emit)
    
        def get_title(self):
            return self.title_edit_le.text()
    
        def get_description(self):
            return self.description_edit_le.text()
    
        def clear_ui(self):
            self.title_edit_le.clear()
            self.description_edit_le.clear()
    
        # def sizeHint(self):
        #     """ Tell the caller how big we are. """
        #     return self.starRating.sizeHint()
    
    
    class ListViewDelegate(QtWidgets.QStyledItemDelegate):
    
        def __init__(self, parent=None):
            super(ListViewDelegate, self).__init__(parent)
    
    
        def sizeHint(self, option, index):
            if index.data(CustomRoles.cur_state):
                return QtCore.QSize(100, 77)
            else:
                return QtCore.QSize(100, 24)
                # return option.rect.size()
                # return QtWidgets.QStyledItemDelegate.sizeHint(self, option, index)
    
        def createEditor(self, parent, option, index):
            print("createEditor")
            item = index.model().itemFromIndex(index)
            item.setData(True, CustomRoles.cur_state)
            editor = Editor(parent)
            editor.editingFinished.connect(self.commitAndCloseEditor)
            editor.title_edit_le.setText(index.data(CustomRoles.title))
            editor.description_edit_le.setText(index.data(CustomRoles.description))
            index.model().layoutChanged.emit()
            return editor
    
    
        def setModelData(self, editor, model, index):
            print("setModelData")
    
            model.setData(index, editor.get_title(), role=CustomRoles.title)
            model.setData(index, editor.get_description(), role=CustomRoles.description)
            model.setData(index, False, role=CustomRoles.cur_state)
            model.setData(index, editor.get_title(), role=Qt.DisplayRole)
    
    
        def commitAndCloseEditor(self):
            print('commitAndCloseEditor')
            editor = self.sender()
            self.commitData.emit(editor)
            self.closeEditor.emit(editor, QtWidgets.QStyledItemDelegate.NoHint)
            self.edit_state = False
            self.parent().layoutChanged.emit()
    
    
    def print_data():
        index = list_view.currentIndex()
        print('*'*20)
        print(index.data(QtCore.Qt.DisplayRole))
        print(index.data(CustomRoles.title))
        print(index.data(CustomRoles.description))
        print(index.data(CustomRoles.cur_state))
    
    
    if __name__ == '__main__':
        app = QtWidgets.QApplication(sys.argv)
        w = QtWidgets.QWidget()
        list_view = QtWidgets.QListView()
        model = QtGui.QStandardItemModel()
        list_view.setModel(model)
        list_view.setItemDelegate(ListViewDelegate(model))
    
        list_items = ['zero', 'one', 'two']
        for i in list_items:
            item = QtGui.QStandardItem(i)
            item.setData(i, CustomRoles.title)
            item.setData("no comment yet", CustomRoles.description)
            item.setData(False, CustomRoles.cur_state)
            model.appendRow(item)
    
        lay = QtWidgets.QVBoxLayout()
        pb = QtWidgets.QPushButton('Print item data')
        pb.clicked.connect(print_data)
        lay.addWidget(list_view)
        lay.addWidget(pb)
        w.setLayout(lay)
        w.show()
        rec = app.exec_()
        sys.exit(rec)
    

  • Banned

    @alom just a heads up so you know someone has looked at this -- I have been working with this to see if I can help you with this issue but it is going to take a bit more effort than some of the simpler questions I have answered here but I will post something later on once I have ironed out the issues


Log in to reply