= Handling context menus = On the #pyqt channel on Freenode, `jams` asked about adding a context menu to a table widget. The context menu policy described by [[http://www.riverbankcomputing.com/static/Docs/PyQt4/html/qt.html#ContextMenuPolicy-enum|Qt.ContextMenuPolicy]] determines how context menus are handled by each widget. To choose a policy, we call its [[http://www.riverbankcomputing.com/static/Docs/PyQt4/html/qwidget.html#setContextMenuPolicy|setContextMenuPolicy()]] method with one of the policy values. The useful policies are `DefaultContextMenu`, `ActionsContextMenu` and `CustomContextMenu`. This means that there are basically three ways to add a context menu to a widget: 1. Subclass the widget and reimplement its [[http://www.riverbankcomputing.com/static/Docs/PyQt4/html/qwidget.html#contextMenuEvent|contextMenuEvent()]] handler method, using the default context menu policy. 2. Add actions to the widget and set the context menu policy to `ActionsContextMenu`. 3. Set the context menu policy to `CustomContextMenu` and connect the widget's [[http://www.riverbankcomputing.com/static/Docs/PyQt4/html/qwidget.html#customContextMenuRequested|customContextMenuRequested()]] signal to a slot or method where a menu can be opened. The code for the examples shown here can be found as attachments to this page: * [[attachment:custommenu_subclass.py]] * [[attachment:custommenu_actions.py]] * [[attachment:custommenu_actions_standard.py]] * [[attachment:custommenu_signal.py]] == Subclassing == If you are writing a custom widget or are subclassing a standard widget, the default subclassing approach is quite convenient. We reimplement the context menu event and create our own menu, making sure that we convert the position passed in the `event` object from local widget coordinates to global screen coordinates. {{{ #!python import sys from PyQt4.QtCore import Qt from PyQt4.QtGui import * class TableWidget(QTableWidget): def __init__(self, parent = None): QTableWidget.__init__(self, parent) def contextMenuEvent(self, event): menu = QMenu(self) quitAction = menu.addAction("Quit") action = menu.exec_(self.mapToGlobal(event.pos())) if action == quitAction: qApp.quit() app = QApplication([]) tableWidget = TableWidget() tableWidget.show() sys.exit(app.exec_()) }}} == Actions == For widgets with built-in actions, we can change the policy to `ActionsContextMenu` and the widget will automatically obtain its own context menu. For widgets without built-in actions, we can add new ones. {{{ #!python import sys from PyQt4.QtCore import Qt from PyQt4.QtGui import * class TableWidget(QTableWidget): def __init__(self, parent = None): QTableWidget.__init__(self, parent) self.setContextMenuPolicy(Qt.ActionsContextMenu) quitAction = QAction("Quit", self) quitAction.triggered.connect(qApp.quit) self.addAction(quitAction) app = QApplication([]) tableWidget = TableWidget() tableWidget.show() sys.exit(app.exec_()) }}} We can even add actions to standard widgets without having to subclass them: {{{ #!python import sys from PyQt4.QtCore import Qt from PyQt4.QtGui import * app = QApplication([]) tableWidget = QTableWidget() tableWidget.setContextMenuPolicy(Qt.ActionsContextMenu) quitAction = QAction("Quit", None) quitAction.triggered.connect(qApp.quit) tableWidget.addAction(quitAction) tableWidget.show() sys.exit(app.exec_()) }}} == Signal and Slot == Sometimes, when we do not want to subclass a standard widget or use actions, it is easier to handle the context menu in a separate component, so we need a way for the widget to notify us when a context menu has been requested. We can do this by changing the policy to `CustomContextMenu` and connecting the widget's `customContextMenuRequested()` signal to a slot, method or function. {{{ #!python import sys from PyQt4.QtCore import Qt from PyQt4.QtGui import * app = QApplication([]) tableWidget = QTableWidget() tableWidget.setContextMenuPolicy(Qt.CustomContextMenu) def openMenu(position): menu = QMenu() quitAction = menu.addAction("Quit") action = menu.exec_(tableWidget.mapToGlobal(position)) if action == quitAction: qApp.quit() tableWidget.customContextMenuRequested.connect(openMenu) tableWidget.show() sys.exit(app.exec_()) }}} The signal delivers a [[http://www.riverbankcomputing.com/static/Docs/PyQt4/html/qpoint.html|QPoint]] value, representing the position of the menu request in local widget coordinates. As before, we convert the position to a global screen position before showing the menu.