菜单示例
“菜单”示例演示了如何在主窗口应用程序中使用菜单。
菜单控件可以是菜单栏中的下拉菜单,也可以是独立的上下文菜单。当下拉菜单中的相应项目被用户点击或按下指定的快捷键时,菜单栏会显示该菜单。上下文菜单通常通过某些特殊的键盘按键或右键单击来调用。

一个菜单由一组操作项组成。在应用程序中,许多常用命令可通过菜单、工具栏按钮以及键盘快捷键来调用。由于用户期望无论使用何种用户界面,命令都能以相同的方式执行,因此将每个命令表示为一个操作是非常有用的。
“Menus”示例由一个类MainWindow 组成,该类继承自QMainWindow 类。当在应用程序中选择某个操作项时,该类会在其中央控件中显示该操作项的路径。
MainWindow 类定义
QMainWindow 提供了一个主应用程序窗口,其中包含菜单栏、工具栏、停靠控件以及围绕大型中央控件的状态栏。
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()函数,以接收控件的上下文菜单事件(请注意,默认实现会直接忽略这些事件)。
每当接收到此类事件时,我们会创建一个包含Cut 、Copy 和Paste 操作的菜单。 右键菜单既可以通过popup()函数异步执行,也可以通过exec()函数同步执行。在此示例中,我们选择使用exec()函数显示菜单。通过将事件的位置作为参数传递,可确保右键菜单出现在预期位置。
© 2026 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.