pythonpyqtpyqt5contextmenuqtablewidgetitem

Modify QTableWidgetItem context menu when editing


I'm trying to add actions to the context menu that pops up when I right click while editing a cell’s content in a QTableWidget. I tried redefining the contextMenuEvent() method from QTableWidget but it is never called in this context. I also tried to call cellWidget() method on the items, but as I expected it returned None. I'm guessing that a temporary QLineEdit widget is created whenever a cell is in edit mode but couldn't find anything to confirm that.

Is there any way to access the context menu of QTableWidgetItems when in edit mode?

I've looked extensively through the documentation but to no avail.


Solution

  • The context menu that you must handle is the editor provided by the delegate. So in this case a QStyledItemDelegate must be implemented:

    from PyQt5 import QtCore, QtGui, QtWidgets
    
    
    class StyledItemDelegate(QtWidgets.QStyledItemDelegate):
        def createEditor(self, parent, option, index):
            editor = super().createEditor(parent, option, index)
            if isinstance(editor, QtWidgets.QLineEdit):
                editor.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
                editor.setProperty("index", QtCore.QPersistentModelIndex(index))
                editor.customContextMenuRequested.connect(self.handle_context_menu)
            return editor
    
        def handle_context_menu(self, pos):
            editor = self.sender()
            if isinstance(editor, QtWidgets.QLineEdit):
                index = editor.property("index")
                menu = editor.createStandardContextMenu()
                action = menu.addAction("New Action")
                action.setProperty("index", index)
                action.triggered.connect(self.handle_add_new_action_triggered)
                menu.exec_(editor.mapToGlobal(pos))
    
        def handle_add_new_action_triggered(self):
            action = self.sender()
            if isinstance(action, QtWidgets.QAction):
                index = action.property("index")
                print(index.row(), index.column(), index.data())
    
    
    if __name__ == "__main__":
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
    
        view = QtWidgets.QTableWidget(3, 5)
        delegate = StyledItemDelegate(view)
        view.setItemDelegate(delegate)
        view.resize(640, 480)
        view.show()
    
        sys.exit(app.exec_())