警告
本节包含从 C++ 自动翻译为 Python 的片段,可能存在错误。
菜单示例#
菜单示例演示了如何在主窗口应用程序中使用菜单。
菜单小部件可以是菜单栏中的下拉菜单或独立的上下文菜单。下拉菜单在用户点击相应项目或按下指定快捷键时通过菜单栏显示。上下文菜单通常通过某些特殊键盘键或通过右键单击来调用。
菜单由一系列 动作 项目组成。在应用中,许多常见命令可以通过菜单、工具栏按钮和键盘快捷键来调用。由于用户期望命令以相同的方式执行,无论使用何种用户界面,因此将每个命令表示为动作非常有用。
菜单示例由一个类组成,即从 QMainWindow
类派生的 MainWindow
。当选择应用中的其中一个动作项时,它将在其中心小部件中显示该项的路径。
MainWindow 类定义#
QMainWindow
提供了一个主应用程序窗口,其中包含菜单栏、工具栏、浮动小部件和围绕一个大型中心小部件的状态栏。
class MainWindow(QMainWindow): Q_OBJECT # public MainWindow() # protected #ifndef QT_NO_CONTEXTMENU def contextMenuEvent(event): #endif // QT_NO_CONTEXTMENU
在这个示例中,我们将看到如何实现下拉菜单以及上下文菜单。为了实现自定义上下文菜单,我们必须重写 QWidget
的 contextMenuEvent()
函数以接收我们的主窗口的上下文菜单事件。
# private slots def newFile(): def open(): def save(): def print(): def undo(): def redo(): def cut(): def copy(): def paste(): def bold(): def italic(): def leftAlign(): def rightAlign(): def justify(): def center(): def setLineSpacing(): def setParagraphSpacing(): def about(): def aboutQt():
我们还必须实现一个私有的任务集合,以响应用户激活我们菜单中的任何菜单项。注意,由于这些任务很简单,即它们中的大多数只是在主窗口的中心小部件中显示动作的路径,所以这些任务被省略在本文档中。
# private def createActions(): def createMenus():
我们选择简化构造函数,通过实现两个私有的方便函数来创建各种动作,将它们添加到菜单中并将它们插入到主窗口的菜单栏中。
fileMenu = QMenu() editMenu = QMenu() formatMenu = QMenu() helpMenu = QMenu() alignmentGroup = QActionGroup() newAct = QAction() openAct = QAction() saveAct = QAction() printAct = QAction() exitAct = QAction() undoAct = QAction() redoAct = QAction() cutAct = QAction() copyAct = QAction() pasteAct = QAction() boldAct = QAction() italicAct = QAction() leftAlignAct = QAction() rightAlignAct = QAction() justifyAct = QAction() centerAct = QAction() setLineSpacingAct = QAction() setParagraphSpacingAct = QAction() aboutAct = QAction() aboutQtAct = QAction() infoLabel = QLabel()
最后,我们在应用程序全范围内声明各种菜单和动作以及一个简单的信息标签。
QMenu
类提供用于菜单栏、上下文菜单和其他弹出菜单的菜单小部件,而 QAction
类提供可以插入到小部件中的抽象用户界面动作。
在某些情况下,将操作分组在一起是有用的,例如,我们有一个左对齐操作,一个右对齐操作,一个两端对齐操作和一个居中对齐操作,我们希望在任何时候只有一个这些操作处于活动状态。实现这一点的一个简单方法是将这些操作组合在一起使用QActionGroup类中的动作组。
MainWindow类实现#
在构造函数中,我们首先创建一个常规QWidget
并将其作为主窗口的中心小部件。请注意,主窗口会在适当的时间接管小部件指针并删除它。
def __init__(self): widget = QWidget() setCentralWidget(widget) topFiller = QWidget() topFiller.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) infoLabel = QLabel(tr("<i>Choose a menu option, or right-click to " "invoke a context menu</i>")) infoLabel.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken) infoLabel.setAlignment(Qt.AlignCenter) bottomFiller = QWidget() bottomFiller.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) layout = QVBoxLayout() layout.setContentsMargins(5, 5, 5, 5) layout.addWidget(topFiller) layout.addWidget(infoLabel) layout.addWidget(bottomFiller) widget.setLayout(layout)
然后我们创建了信息标签以及顶部和底部填充,并将它们添加到一个布局中,然后安装到中心小部件上。《a class="reference internal" href="../PySide6/QtWidgets/QMainWindow.html#PySide6.QtWidgets.QMainWindow" title="PySide6.QtWidgets.QMainWindow">QMainWindow
对象自带自定义布局,将布局设置在真实主窗口上,或创建以主窗口作为父级的布局,均被视为错误。您始终应在自己的中心小部件上设置自己的布局。
createActions() createMenus() message = tr("A context menu is available by right-clicking") statusBar().showMessage(message) setWindowTitle(tr("Menus")) setMinimumSize(160, 160) resize(480, 320)
为了创建操作和菜单,我们调用我们的两个便捷函数:createActions()
和createMenus()
。稍后我们将回到这些功能。
使用QMainWindow
的statusBar()
函数可以返回主窗口的状态条(如果状态条不存在,此函数会创建并返回一个空状态条)。我们初始化状态条和窗口标题,将窗口调整到适当的大小,并确保主窗口的尺寸不能小于给定值。
现在,让我们仔细看看创建各种操作的便捷函数createActions()
def createActions(self): newAct = QAction(QIcon.fromTheme(QIcon.ThemeIcon.DocumentNew), tr("New"), self) newAct.setShortcuts(QKeySequence.New) newAct.setStatusTip(tr("Create a file()")) newAct.triggered.connect(self.newFile) ...
QAction对象可以包含图标、文本、快捷键、状态提示、“这是什么”文本和工具提示。其中大部分可以在构造函数中设置,但也可以使用提供的便捷函数独立设置。
在createActions()
函数中,我们首先创建一个名为newAct
的操作,通过使用一个主题图标常量传递文本和图标。我们使用QAction::setShortcut()函数使其快捷键为Ctrl+N,并使用QAction::setStatusTip()函数设置其状态提示(状态提示显示在操作顶级父小部件提供的所有状态条上)。我们还连接其triggered()信号到newFile()
槽。
其余的操作以类似的方式创建。请参阅源代码以获取详细信息。
alignmentGroup = QActionGroup(self) alignmentGroup.addAction(leftAlignAct) alignmentGroup.addAction(rightAlignAct) alignmentGroup.addAction(justifyAct) alignmentGroup.addAction(centerAct) leftAlignAct.setChecked(True)
一旦我们创建了左对齐、右对齐、两端对齐和居中对齐操作,我们还可以创建之前提到的动作组。
我们使用QActionGroup的addAction()函数将每个操作添加到组中。请注意,也可以通过将其创建为具有组作为其父级来将操作添加到组中。由于动作组默认是互斥的,因此组中的任何操作在任何时候都只能被选中(这可以通过使用QActionGroup::setExclusive()函数来改变)。
当所有操作创建完成后,我们使用 createMenus()
函数将操作添加到菜单中,并将菜单插入到菜单栏中。
def createMenus(self): fileMenu = menuBar().addMenu(tr("File")) fileMenu.addAction(newAct) fileMenu.addAction(openAct) fileMenu.addAction(saveAct) fileMenu.addAction(printAct) fileMenu.addSeparator() fileMenu.addAction(exitAct) editMenu = menuBar().addMenu(tr("Edit")) editMenu.addAction(undoAct) editMenu.addAction(redoAct) editMenu.addSeparator() editMenu.addAction(cutAct) editMenu.addAction(copyAct) editMenu.addAction(pasteAct) editMenu.addSeparator() helpMenu = menuBar().addMenu(tr("Help")) helpMenu.addAction(aboutAct) helpMenu.addAction(aboutQtAct)
QMenuBar
的 addMenu()
函数可以向菜单栏追加带有指定标题的新 QMenu
(请注意,菜单栏将拥有该菜单的所有权)。我们使用 QWidget
的 addAction()
函数将每个操作添加到对应的菜单中。
另外,QMenu
类提供了一些 addAction()
便利函数,这些函数可以从给定的文本和/或图标中创建并添加新操作。您还可以提供一个将自动连接到新操作 triggered() 信号的成员,以及一个由 QKeySequence 实例表示的快捷键。
addSeparator()
函数创建并返回一个新的分隔符操作,即一个返回 true 的 QAction::isSeparator() 的操作,并将新操作添加到菜单的动作列表中。
formatMenu = editMenu.addMenu(tr("Format")) formatMenu.addAction(boldAct) formatMenu.addAction(italicAct) formatMenu.addSeparator().setText(tr("Alignment")) formatMenu.addAction(leftAlignAct) formatMenu.addAction(rightAlignAct) formatMenu.addAction(justifyAct) formatMenu.addAction(centerAct) formatMenu.addSeparator() formatMenu.addAction(setLineSpacingAct) formatMenu.addAction(setParagraphSpacingAct)
注意格式菜单。首先,它被用作 Edit 菜单的子菜单添加到菜单栏,使用 QMenu
的 addMenu()
函数添加。其次,看看对齐操作:在 createActions() 函数中,我们向动作组添加了 leftAlignAct、rightAlignAct、justifyAct 和 centerAct 动作。尽管如此,我们必须单独将每个操作添加到菜单中,而动作组则在幕后执行其魔法。
#ifndef QT_NO_CONTEXTMENU def contextMenuEvent(self, event): menu = QMenu(self) menu.addAction(cutAct) menu.addAction(copyAct) menu.addAction(pasteAct) menu.exec(event.globalPos()) #endif // QT_NO_CONTEXTMENU
要提供自定义上下文菜单,我们必须重新实现 QWidget
的 contextMenuEvent()
函数,以接收小部件的上下文菜单事件(请注意,默认实现简单地忽略这些事件)。
每当接收到此类事件时,我们会创建一个包含剪切、复制和粘贴操作的菜单。上下文菜单可以异步或同步执行。异步执行可以使用popup()
函数,同步执行可以使用exec()
函数。在此例中,我们选择使用其exec()
函数来显示菜单。通过传递事件的位置作为参数,我们确保上下文菜单出现在预期的位置。