Glyphosate
Glyphosate

Reputation: 13

PyQt extend existing Contextual Menu when editing QstandardItem's Text (in a QtreeView)

I would like to add an action to the "default" Contextual menu that shows up when editing QStandardItem's Text (wich is shown in a QTreeView)

This contextual menu seems to be the default contextual menu of QPlainTextEdit widget. There is the default actions : Undo, Redo, Copy, Paste, Delete, Select All. I want to add a custom action just here.

I have no clue on how to modify this menu.

Thanks in advance !

Upvotes: 0

Views: 2863

Answers (2)

three_pineapples
three_pineapples

Reputation: 11869

To customise the editor for a QTreeView cell you need to create a QItemDelegate and associate it with a column of your treeview.

Custom delegates can be more complex (eg to change the save/restore behaviour of the editor) but in this case we just want to change which class it is using to instantiate the editor widget:

class CustomDelegate(QItemDelegate):
    def createEditor(self, parent, option, index):
        editor = CustomLineEdit(parent)                
        return editor

This will ensure the editor is now a CustomLineEdit widget, which can have any added functionality you wish (like a custom context menu). In my example below, I use a slightly modified version of the answer provided by Achayan to implement this CustomLineEdit.

You assign a custom delegate to a column with the following code (in this case I've chosen column 0 of the treeview):

# Create custom Delegate which instantiates our custom editor
delegate = CustomDelegate()
# Set this delegate for the first column only
treeview.setItemDelegateForColumn(0, delegate)

Full Code

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class CustomLineEdit(QLineEdit):
    def __init__(self, *args, **kwargs):
        super(CustomLineEdit, self).__init__(*args, **kwargs)
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.__contextMenu)

    def __contextMenu(self):
        self._normalMenu = self.createStandardContextMenu()
        self._addCustomMenuItems(self._normalMenu)
        self._normalMenu.exec_(QCursor.pos())

    def _addCustomMenuItems(self, menu):
        menu.addSeparator()
        menu.addAction(u'Test', self.testFunc)

    def testFunc(self):
        print "Call"


class CustomDelegate(QItemDelegate):
    def createEditor(self, parent, option, index):
        editor = CustomLineEdit(parent)                
        return editor


if __name__ == "__main__":
    app = QApplication(sys.argv)

    # Create Widgets
    window = QMainWindow()
    widget = QWidget()
    layout = QVBoxLayout(widget)
    treeview = QTreeView()
    layout.addWidget(treeview)
    window.setCentralWidget(widget)
    window.show()

    # Create Model
    model = QStandardItemModel()
    model.setHorizontalHeaderLabels(['Header 1','Header 2'])
    treeview.setModel(model)

    # Create custom Delegate which instantiates our custom editor
    delegate = CustomDelegate()
    # Set this delegate for the first column only
    treeview.setItemDelegateForColumn(0, delegate)

    # Populate the model with some test data
    row1 = []
    row1.append(QStandardItem("asd"))
    row1.append(QStandardItem("fgh"))
    model.appendRow(row1)
    row2 = []
    row2.append(QStandardItem("qwe"))
    row2.append(QStandardItem("rty"))
    model.appendRow(row2)

    app.exec_()

Upvotes: 3

Achayan
Achayan

Reputation: 5895

I have a example for QPlainTextEdit. You can modify based on your need. Hope this helps

class CustomLineEdit(QtGui.QPlainTextEdit):
    def __init__(self, parent = None):
        super(CustomLineEdit, self).__init__()
        self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.__contextMenu)

    def __contextMenu(self):
        self._normalMenu = self.createStandardContextMenu()
        self._addCustomMenuItems(self._normalMenu)
        self._normalMenu.exec_(QtGui.QCursor.pos())

    def _addCustomMenuItems(self, menu):
        menu.addSeparator()
        menu.addAction(u'Test', self.testFunc)

    def testFunc(self):
        print "Call"

class mainwindow(QtGui.QWidget):
    def __init__(self , parent = None):
        super(mainwindow, self).__init__()    
        self.setupgui()
    def setupgui(self):

        self.resize(800,600)
        self.setWindowTitle('test')
        newLayout = QtGui.QHBoxLayout()
        qlbl = CustomLineEdit()
        newLayout.addWidget(qlbl)
        self.setLayout(newLayout)
        self.show()


def main():

    app = QtGui.QApplication(sys.argv)
    ex = mainwindow()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

Upvotes: 1

Related Questions