菜单示例
菜单示例演示了如何在主窗口应用程序中使用菜单。
菜单部件既可以是菜单栏中的下拉菜单,也可以是独立的上下文菜单。当用户点击相应项目或按下指定的快捷键时,菜单栏就会显示下拉菜单。上下文菜单通常通过一些特殊的键盘键或右键单击来调用。
菜单由一系列操作项目组成。在应用程序中,许多常用命令都可以通过菜单、工具栏按钮和键盘快捷键调用。由于无论使用何种用户界面,用户都希望以相同的方式执行命令,因此将每个命令表示为一个操作是非常有用的。
菜单示例由一个类MainWindow
组成,该类派生于QMainWindow 类。在我们的应用程序中选择一个操作项时,它将在中心部件中显示该项的路径。
MainWindow 类定义
QMainWindow MainWindow 类提供了一个主应用程序窗口,在一个大的中心部件周围有菜单栏、工具栏、停靠部件和状态栏。
class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(); protected: #ifndef QT_NO_CONTEXTMENU void contextMenuEvent(QContextMenuEvent *event) override; #endif // QT_NO_CONTEXTMENU
在本例中,我们将了解如何实现下拉菜单和上下文菜单。为了实现自定义上下文菜单,我们必须重新实现QWidget 的contextMenuEvent() 函数,以接收主窗口的上下文菜单事件。
private slots: void newFile(); void open(); void save(); void print(); void undo(); void redo(); void cut(); void copy(); void paste(); void bold(); void italic(); void leftAlign(); void rightAlign(); void justify(); void center(); void setLineSpacing(); void setParagraphSpacing(); void about(); void aboutQt();
我们还必须实现一组私有插槽,以响应用户激活任何菜单项的操作。需要注意的是,这些插槽在本文档中没有提及,因为它们都很琐碎,也就是说,其中大部分插槽只是在主窗口的中央部件中显示操作路径。
private: void createActions(); void createMenus();
我们选择简化构造函数,通过实现两个私有的便捷函数来创建各种操作,将它们添加到菜单中,并将菜单插入主窗口的菜单栏。
QMenu *fileMenu; QMenu *editMenu; QMenu *formatMenu; QMenu *helpMenu; QActionGroup *alignmentGroup; QAction *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; QLabel *infoLabel; };
最后,我们在应用程序广域中声明了各种菜单和操作以及一个简单的信息标签。
QMenu 类提供了一个菜单部件,可用于菜单栏、上下文菜单和其他弹出式菜单,而QAction 类则提供了一个抽象的用户界面操作,可插入到部件中。
在某些情况下,将操作组合在一起是非常有用的,例如,我们有一个Left Align 操作、一个Right Align 操作、一个Justify 操作和一个Center 操作,而我们希望在任何时候这些操作中只有一个处于活动状态。实现这一点的一个简单方法是使用QActionGroup 类将这些操作组合到一个操作组中。
MainWindow 类的实现
在构造函数中,我们首先创建一个常规的QWidget ,并将其作为主窗口的中心部件。请注意,主窗口拥有部件指针的所有权,并在适当的时候将其删除。
MainWindow::MainWindow() { QWidget *widget = new QWidget; setCentralWidget(widget); QWidget *topFiller = new QWidget; topFiller->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); infoLabel = new 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); QWidget *bottomFiller = new QWidget; bottomFiller->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); QVBoxLayout *layout = new QVBoxLayout; layout->setContentsMargins(5, 5, 5, 5); layout->addWidget(topFiller); layout->addWidget(infoLabel); layout->addWidget(bottomFiller); widget->setLayout(layout);
然后,我们创建信息标签以及顶部和底部填充物,并将其添加到安装在中心窗口部件上的布局中。QMainWindow 对象自带自定义布局,在实际主窗口上设置布局或创建以主窗口为父对象的布局都是错误的。您应始终在中心部件上设置自己的布局。
createActions(); createMenus(); QString 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()
方便函数:
void MainWindow::createActions() { newAct = new QAction(QIcon::fromTheme(QIcon::ThemeIcon::DocumentNew), tr("&New"), this); newAct->setShortcuts(QKeySequence::New); newAct->setStatusTip(tr("Create a new file")); connect(newAct, &QAction::triggered, this, &MainWindow::newFile); ...
QAction 对象可能包含一个图标、一段文字、一个快捷方式、一个状态提示、一段 "这是什么?"文字和一个工具提示。其中大部分可以在构造函数中设置,但也可以使用所提供的便利函数单独设置。
在createActions()
函数中,我们首先创建一个newAct
操作,使用主题图标常量之一传递文本和图标。我们使用QAction::setShortcut() 函数使Ctrl+N 成为其快捷方式,并使用QAction::setStatusTip() 函数设置其状态提示(状态提示将显示在该操作的顶层父部件提供的所有状态栏上)。我们还将triggered() 信号连接到newFile()
插槽。
其余动作的创建方式与此类似。详情请查看源代码。
alignmentGroup = new QActionGroup(this); alignmentGroup->addAction(leftAlignAct); alignmentGroup->addAction(rightAlignAct); alignmentGroup->addAction(justifyAct); alignmentGroup->addAction(centerAct); leftAlignAct->setChecked(true); }
创建了Left Align 、Right Align 、Justify 和Center 操作后,我们还可以创建前面提到的操作组。
每个动作都是通过QActionGroup 的addAction() 函数添加到组中的。需要注意的是,也可以通过创建以组为父对象的操作来将该操作添加到组中。由于默认情况下动作组是排他的,因此任何时候都只能检查组中的一个动作(可以使用QActionGroup::setExclusive() 函数更改)。
创建完所有操作后,我们使用createMenus()
函数将操作添加到菜单中,并将菜单插入菜单栏:
void MainWindow::createMenus() { 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 实例表示的快捷方式。
QMenu::addSeparator() 函数创建并返回一个新的分隔符动作,即QAction::isSeparator() 返回 true 的动作,并将新动作添加到菜单的动作列表中。
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); }
请注意Format 菜单。首先,它是使用QMenu 的addMenu() 函数作为子菜单添加到Edit 菜单中的。其次,看看对齐操作:在createActions()
函数中,我们将leftAlignAct
、rightAlignAct
、justifyAct
和centerAct
添加到了一个操作组中。不过,我们必须将每个操作分别添加到菜单中,而操作组则在幕后执行其魔法。
#ifndef QT_NO_CONTEXTMENU void MainWindow::contextMenuEvent(QContextMenuEvent *event) { QMenu menu(this); menu.addAction(cutAct); menu.addAction(copyAct); menu.addAction(pasteAct); menu.exec(event->globalPos()); } #endif // QT_NO_CONTEXTMENU
要提供自定义上下文菜单,我们必须重新实现QWidget 的contextMenuEvent() 函数,以接收 widget 的上下文菜单事件(请注意,默认实现只是忽略这些事件)。
每当接收到此类事件,我们就会创建一个包含Cut 、Copy 和Paste 操作的菜单。上下文菜单可以使用popup() 函数异步执行,也可以使用exec() 函数同步执行。在本例中,我们选择使用exec() 函数显示菜单。通过将事件的位置作为参数传递,我们可以确保上下文菜单出现在预期位置。
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.