Search code examples
pythonqtpyqtqt4qt5

How to make sure the ItemDelegate is properly positioned


Code below creates a single QTableView with three Items. Double-clicking any Item brings up a QComboBox which is created by QItemDelegate. The problem is that the QComboBox shows up somewhere on a screen and not where it is expected. What is wrong with the code?

enter image description here

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *    
app = QApplication([])    

class ItemDelegate(QItemDelegate):
    def __init__(self, parent):
        QItemDelegate.__init__(self, parent)

    def createEditor(self, parent, option, index):
        return QComboBox()


class Model(QAbstractTableModel):
    def __init__(self):
        QAbstractTableModel.__init__(self)
        self.items = [[1, 'one', 'ONE'], [2, 'two', 'TWO'], [3, 'three', 'THREE']]

    def flags(self, index):
        return Qt.ItemIsEnabled | Qt.ItemIsEditable

    def rowCount(self, parent=QModelIndex()):
        return 3

    def columnCount(self, parent=QModelIndex()):
        return 3

    def data(self, index, role):
        if not index.isValid():
            return

        if role in [Qt.DisplayRole, Qt.EditRole]:
            return self.items[index.row()][index.column()]


tableModel = Model()
view = QTableView()
view.setModel(tableModel)
view.setItemDelegate(ItemDelegate(view))

view.show()
app.exec_()

Solution

  • You need to specify parent object when returning QComboBox(parent):

    enter image description here

    from PyQt5.QtWidgets import *
    from PyQt5.QtCore import *
    
    app = QApplication([])
    
    
    class ItemDelegate(QItemDelegate):
        def __init__(self, parent):
            QItemDelegate.__init__(self, parent)
    
        def createEditor(self, parent, option, index):
            combo = QComboBox(parent)
            combo.addItems(['One', 'Two', 'Three'])
            return combo
    
    
    class Model(QAbstractTableModel):
        def __init__(self):
            QAbstractTableModel.__init__(self)
            self.items = [[1, 'one', 'ONE'], [2, 'two', 'TWO'], [3, 'three', 'THREE']]
    
        def flags(self, index):
            return Qt.ItemIsEnabled | Qt.ItemIsEditable
    
        def rowCount(self, parent=QModelIndex()):
            return 3
    
        def columnCount(self, parent=QModelIndex()):
            return 3
    
        def data(self, index, role):
            if not index.isValid():
                return
    
            if role in [Qt.DisplayRole, Qt.EditRole]:
                return self.items[index.row()][index.column()]
    
    
    class MainWindow(QMainWindow):
        def __init__(self, parent=None):
            QMainWindow.__init__(self, parent)
            self.clipboard = QApplication.clipboard()
            mainWidget = QWidget()
            self.setCentralWidget(mainWidget)
    
            mainLayout = QVBoxLayout()
            mainWidget.setLayout(mainLayout)
    
            view = QTableView()
            model = Model()
            view.setModel(model)
            view.setItemDelegate(ItemDelegate(view))
    
            column = 2
            for row in range(3):
                view.openPersistentEditor(view.model().index(row, column))
    
            mainLayout.addWidget(view)
    
    
    view = MainWindow()
    view.show()
    app.exec_()