15、为控件添加右键菜单

Par @Martin dans le
Tags :

参考资料:
Qt QWidget 添加右键菜单
QTableWidget 详解

编程中, 右键菜单是必不可少的, 特别是应用在 Table 类的控件上.

添加 Action

参考之前学 Qt 的系列笔记: 13、资源文件及 Action

Qt 中, 每个菜单项是一个 Action, 我们要显示右键菜单, 也要先定义好 Action, 方法就参考上面的笔记, 在 Qt 设计师中添加, 也可以像下面这样, 自己在代码中添加.

from PyQt4.QtGui import QMenu, QAction

def on_open():
    print u'打开'

def on_download():
    print u'下载'

self.pop_menu = QMenu()

self.action_open = QAction(self)
self.action_open.setText(u"打开")
self.action_open.triggered.connect(on_open)

self.action_download = QAction(self)
self.action_download.setText(u"下载")
self.action_download.triggered.connect(on_download)


添加菜单

这里有两种方法, 一种是基于事件, 另一种是基于信号槽

重写事件

Qt 的控件都有一个右键菜单事件 contextMenuEvent, 我们重写这个事件就可以了:

self.contextMenuEvent = self.e_contextMenuEvent

def e_contextMenuEvent(self, event):
    self.pop_menu.clear()  # 清除原有菜单
    self.pop_menu.addAction(self.action_open)
    self.pop_menu.addSeparator()  # 分隔线
    self.pop_menu.addAction(self.action_download)
    self.pop_menu.exec_(event.globalPos())
    event.accept()


如果想添加次级菜单, 可以使用 pop_menu.addMenu:

def e_contextMenuEvent(self, event):
    self.pop_menu.clear()
    self.pop_menu.addAction(self.action_open)
    secondary_menu = self.pop_menu.addMenu(u'其它')
    secondary_menu.addAction(self.action_download)
    self.pop_menu.exec_(event.globalPos())
    event.accept()


如果是在 Table 类的控件上, 你可以还需要得到当前鼠标所在的 item:

point = event.pos()
item = self.tableWidgetItem.itemAt(point)
if item != None:
    pass


要注意, itemAt 使用的是局部坐标, exec_ 使用的是全局坐标.

关联信号槽

这种方法的机制是为控件建立 press 的信号槽, 在槽函数里判断是左键还是右键, 这种方法对有 item 的控件支持比较好, 如: QListWidget、QTableWidget、QTreeWidget.

以 QTableWidget 为例, 我们先在主窗体上拖一个 QTableWidget:

self.tableWidget.itemPressed.connect(self.on_item_clicked)  # 关联信号槽

def on_item_clicked(self, item):
    if QtGui.qApp.mouseButtons() == QtCore.Qt.LeftButton:
        return
    elif QtGui.qApp.mouseButtons() == QtCore.Qt.RightButton:
        self.show_menu()

def show_menu(self):
    self.pop_menu.clear()
    self.pop_menu.addAction(self.action_open)
    secondary_menu = self.pop_menu.addMenu(u'其它')
    secondary_menu.addAction(self.action_download)
    self.pop_menu.exec_(QtGui.QCursor.pos())


可以看到, 这种方法我们很方便的就得到了一个 item 对象, 而不需要像事件里那样使用 itemAt().