文章目录
-
- 1、概要
-
- [1.1、基于 QAction 的 QMenu 实现模式](#1.1、基于 QAction 的 QMenu 实现模式)
- [1.2、 通过按钮触发的 QMenu 实现(ui)](#1.2、 通过按钮触发的 QMenu 实现(ui))
- 1.3、菜单触发显示自定义窗口(ui)
1、概要
在 Qt 界面开发中,QMenu 是构建交互菜单的核心组件,其实现方式直接影响菜单的灵活性与易用性。本文将聚焦两种主流实现模式 ------ 基于
QAction 的联动模式和直接通过按钮触发的模式,深入解析它们的实现逻辑、适用场景及优劣势,帮助开发者根据实际需求选择最优方案。
1.1、基于 QAction 的 QMenu 实现模式
(1)、什么是 QAction?
QAction 是 Qt 中用于封装用户操作的对象,它可以关联菜单、工具栏等组件,集中管理操作的文本、图标、快捷键及触发逻辑。
在 QMenu 中,QAction 是菜单选项的 "灵魂",菜单的显示与功能触发均围绕它展开。
(2)、实现步骤
cpp
//创建QAction对象
QAction *actionNew = new QAction(QIcon("new.png"), tr("新建(&N)"), this);
actionNew->setShortcut(QKeySequence::New);
connect(actionNew, &QAction::triggered, this, &MainWindow::onNewFile);
cpp
//构建 QMenu 并关联 QAction
QMenu *fileMenu = menuBar()->addMenu(tr("文件(&F)"));
fileMenu->addAction(actionNew);
fileMenu->addSeparator(); // 添加分隔线
1.2、 通过按钮触发的 QMenu 实现(ui)
(1)、实现效果
QMenu
(2)、具体实现
cpp
//mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMenu>
#include <QMap>
#include <QDebug>
#include <QMouseEvent>
#include <QPoint>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
void installMenuEventFilters(); //安装事件过滤器到所有菜单标题
bool eventFilter(QObject* obj, QEvent* event); //事件过滤器:捕捉菜单标题的鼠标点击事件
void onMenubar_even(QMenu* menu);
signals:
void menuClicked(QMenu* menu);
private:
Ui::MainWindow *ui;
QMap<QMenu*, QAction*> menuToActionMap;
};
#endif // MAINWINDOW_H
cpp
//mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(this,&MainWindow::menuClicked,this,&MainWindow::onMenubar_even);
installMenuEventFilters();
}
MainWindow::~MainWindow(){delete ui;}
void MainWindow::onMenubar_even(QMenu* menu)
{
if (!menu) {
qDebug() << "错误:接收到空菜单指针";
return;
}
// 检查tabWidget是否存在
if (!ui->tabWidget) {
qDebug() << "错误:tabWidget未初始化";
return;
}
QString objName = menu->objectName();
if (objName == "menuA") {
ui->tabWidget->setCurrentIndex(0);
}else if(objName == "menuB")
{
ui->tabWidget->setCurrentIndex(1);;
}else if(objName == "menuC")
{
ui->tabWidget->setCurrentIndex(0);
}
}
// 安装事件过滤器到所有菜单标题
void MainWindow::installMenuEventFilters() {
// 遍历菜单栏中的所有动作
for (QAction* action : ui->menubar->actions()) {
QMenu* menu = action->menu();
if (menu) {
menuToActionMap[menu] = action;
ui->menubar->installEventFilter(this);
}
}
}
// 事件过滤器:捕获菜单标题的鼠标点击事件
bool MainWindow::eventFilter(QObject* obj, QEvent* event){
if (obj == ui->menubar && event->type() == QEvent::MouseButtonRelease) {
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
QPoint pos = mouseEvent->pos();
for (auto it = menuToActionMap.begin(); it != menuToActionMap.end(); ++it) {
QMenu* menu = it.key();
QAction* action = it.value();
QRect actionRect = ui->menubar->actionGeometry(action);
if (actionRect.contains(pos)) {
emit menuClicked(menu);
return true;
}
}
}
return QMainWindow::eventFilter(obj, event);
}
1.3、菜单触发显示自定义窗口(ui)
(1)、功能描述
从技术实现角度,这种功能的核心是:
(a)、监听 QMenu 中特定菜单项(QAction 或自定义部件)的触发信号
(b)、在信号处理函数中调用 QWidget 的show()、exec()(模态)或popup()等方法显示窗口
(2)、实现效果
QMenu菜单触发显示自定义弹框
(3)、具体实现
cpp
//mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QDebug>
#include <QTextCursor>
#include <QListView>
#include <QListView>
#include <QAbstractItemView>
#include "doubleclickfoldwidget.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots: //QTextEdit
void on_fruitParty_triggered();
private:
Ui::MainWindow *ui;
FruitPartyWidget *m_fruitPartyWidget; //初始化自定义窗口类
};
#endif // MAINWINDOW_H
cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_doubleClickFoldWidget=new DoubleClickFold();//初始化自定义窗口类
}
MainWindow::~MainWindow()
{
delete ui;
if(m_doubleClickFoldWidget){delete m_doubleClickFoldWidget;m_doubleClickFoldWidget=nullptr;}
}
void MainWindow::on_fruitParty_triggered()
{
m_fruitPartyWidget->show();
}
//自定义窗口类,实现了双击QLable折叠QWidget
//fruit_party_widget.ui
cpp
//fruit_party_widget.h
#include <QLabel>
#include <QMouseEvent>
class FruitPartyWidget : public QWidget
{
Q_OBJECT
public:
explicit FruitPartyWidget(QWidget *parent = nullptr);
~FruitPartyWidget();
protected:
bool eventFilter(QObject *obj, QEvent *event) override; // 重写事件过滤器,用于捕获子部件的事件
private slots:
void toggleWidgetVisibility();// 切换窗口部件可见性的槽函数(折叠/展开)
private:
Ui::FruitPartyWidget *ui;
};
cpp
//fruit_party_widget.cpp
FruitPartyWidget::FruitPartyWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::DoubleClickFold)
{
ui->setupUi(this);
// 为 QLabel 安装事件过滤器以捕获点击事件
ui->label->installEventFilter(this);
}
// 重写事件过滤器,用于捕获子部件的事件
bool FruitPartyWidget::eventFilter(QObject *obj, QEvent *event)
{
//判断事件来源是否为label,且事件类型为鼠标双击
if (obj == ui->label && event->type() == QEvent::MouseButtonDblClick) {
toggleWidgetVisibility();// 双击时触发窗口可见性切换(折叠/展开)
return true;
}
return QObject::eventFilter(obj, event);// 未处理的事件交给父类默认处理
}
// 切换窗口部件可见性的槽函数(折叠/展开)
void FruitPartyWidget::toggleWidgetVisibility()
{
bool isVisible = ui->widget->isVisible();
ui->widget->setVisible(!isVisible);
}