使用 PyQt5 创建上下文菜单

Posted

技术标签:

【中文标题】使用 PyQt5 创建上下文菜单【英文标题】:Create a context menu with PyQt5 【发布时间】:2020-12-19 15:01:02 【问题描述】:

我正在尝试制作一个上下文菜单,但我看到了一些他们在其中编写下一个代码的 tuts,例如:

import sys
from PyQt5.QtWidgets import QMainWindow, qApp, QMenu, QApplication


class Example(QMainWindow):

    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('Context menu')
        self.show()

    def contextMenuEvent(self, event):
        cmenu = QMenu(self)

        newAct = cmenu.addAction("New")
        openAct = cmenu.addAction("Open")
        quitAct = cmenu.addAction("Quit")
        action = cmenu.exec_(self.mapToGlobal(event.pos()))

        if action == quitAct:
            qApp.quit()


def main():
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

我尝试在我的代码中实现有 2 个模块但不起作用:

main.py

import win0 as w0
from PyQt5.QtWidgets import QMainWindow, QApplication, QMenu

class Main(QMainWindow, w0.Ui_win0):
    win0 = None
    __win0_ui = None

    def __init__(self):
        self.win0 = QMainWindow()
        self.__win0_ui = w0.Ui_win0()
        self.__win0_ui.setupUi(self.win0)
        self.win0.show()

if __name__ == "__main__":
    import sys
    app = QApplication(sys.argv)
    main = Main()
    app.setStyle("Fusion")
    sys.exit(app.exec_())

win0.py

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QTableWidget, QFrame, QMenu, QMainWindow, qApp

class Table(QTableWidget, QMainWindow):

    def contextMenuEvent(self, event):
        cmenu = QMenu(self)
        newAct = cmenu.addAction("New")
        openAct = cmenu.addAction("Open")
        quitAct = cmenu.addAction("Quit")
        action = cmenu.exec_(self.mapToGlobal(event.pos()))

        if action == quitAct:
            qApp.quit()        

class Ui_win0(object):
    def setupUi(self, win0):
        win0.setObjectName("win0")
        win0.resize(703, 757)
        win0.setStyleSheet("background-color: rgba(29, 29, 29);"
                           "\ncolor: rgb(171, 171, 171);")
        self.centralwidget = QtWidgets.QWidget(win0)
        self.centralwidget.setObjectName("centralwidget")


        self.table1 = Table(self.centralwidget)
        
        # Code...

        self.retranslateUi(win0)
        QtCore.QMetaObject.connectSlotsByName(win0)

    def retranslateUi(self, win0):
        # Code...

我没有粘贴所有代码,不要让它太长,但我想在 Table 类中实现示例,因为我想扩展一些选项或其他选项,具体取决于光标是否位于表格列表上或窗口的其他地方。

我做错了什么?

编辑 1 --------------------------------------------- ----------------------------------------- 为了更清楚,这是下一个想法

白框代表右键单击窗口不同位置的上下文菜单

【问题讨论】:

我很想帮助你,但我不得不承认你的结构不仅是错误的(例如,QObject/QWidget的多重继承是不允许的)而且真的很复杂,很混乱.你能澄清一下你真正想要显示的界面(带有表格小部件的主窗口),以及应该显示菜单的小部件吗?最后,请记住,您不应尝试模仿 pyuic 生成文件的行为(就像您对 Ui_win0 类所做的那样);这些文件背后的概念仅用于设计器文件,没有必要对代码创建的 ui 做同样的事情。 谢谢,我进行了编辑,以便更清晰地附加我想要制作的界面图像 考虑到有这么多空白空间的界面不是一件好事,特别是因为表格需要更多的滚动而不是它至少可以占据整个垂直空间;另外,我相信您没有使用任何布局管理器,这将产生另一个 bad 副作用:如果窗口被调整为更小的尺寸(由用户调整,或者由系统调整,如果屏幕是不够大),表格将被“剪裁”,可能使滚动条无法使用。 我没有使用所有空间,因为我正在考虑在未来将其他小部件放在那里,通过这个示例,我只是想了解如何制作我描述的上下文菜单多于。只是缩小版 【参考方案1】:

我将提供一个“模板代码”,因为所提供的内容由于各种原因(错误的继承、不必要的对象层、不需要的函数和实现)几乎无法使用。

在以下示例中,我混合使用了两种可能的方法来创建菜单事件:

在子类上实现contextMenuEvent() customContextMenuRequested 没有子类化的信号连接
class Table(QtWidgets.QTableWidget):
    def contextMenuEvent(self, event):
        menu = QtWidgets.QMenu()
        index = self.indexAt(event.pos())
        someAction = menu.addAction('')
        if index.isValid():
            someAction.setText('Selected item: ""'.format(index.data()))
        else:
            someAction.setText('No selection')
            someAction.setEnabled(False)
        anotherAction = menu.addAction('Do something')

        res = menu.exec_(event.globalPos())
        if res == someAction:
            print('first action triggered')


class Example(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        central = QtWidgets.QWidget()
        self.setCentralWidget(central)
        layout = QtWidgets.QHBoxLayout(central)
        self.table = Table(10, 4)
        layout.addWidget(self.table)
        layout.addStretch()

        central.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        central.customContextMenuRequested.connect(self.emptySpaceMenu)

    def emptySpaceMenu(self):
        menu = QtWidgets.QMenu()
        menu.addAction('You clicked on the empty space')
        menu.exec_(QtGui.QCursor.pos())


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    example = Example()
    example.show()
    sys.exit(app.exec_())

如您所见,您使用的大部分结构都被视为不必要或多余的。这是一个非常重要的方面:虽然保持高度明确和“冗长”的对象结构通常允许更好的抽象,但过度这样做只会使事情变得不必要地复杂和非常混乱,甚至对程序员来说也是如此。

【讨论】:

以上是关于使用 PyQt5 创建上下文菜单的主要内容,如果未能解决你的问题,请参考以下文章

PyQt5:如何从系统托盘图标上下文菜单启动窗口?

PyQt5不同方法创建菜单栏工具栏和状态栏

PyQt5 QTableWidget:右键选择列,并在上下文菜单中显示删除条目

PyQt5 (Python):通过 contextmenu 从 qpushbutton 获取值

Python PyQt5 QTableWidget contextMenuEvent setStyleSheet 子菜单背景色

将上下文菜单添加到特定的 Qtablewdiget 表列,Python