在Qt窗口中添加右键菜单
- 基于鼠标的事件实现
- 流程
- demo
- 基于窗口的菜单策略实现
- Qt::DefaultContextMenu
- Qt::ActionsContextMenu
- Qt::CustomContextMenu
- 信号API
基于鼠标的事件实现
流程
需要使用:事件处理器函数(回调函数)
- 在当前窗口类中重写鼠标操作相关的的事件处理器函数,有两个可以选择
// 以下两个事件二选一即可, 只是事件函数被调用的时机不同罢了
// 这个时机对右键菜单的显示没有任何影响
[virtual protected] void QWidget::mousePressEvent(QMouseEvent *event);
[virtual protected] void QWidget::mouseReleaseEvent(QMouseEvent *event);
- 在数据表事件处理器函数内部判断是否按下了鼠标右键
- 如果按下了鼠标右键创建菜单对象(也可以提前先创建处理), 并将其显示出来
// 关于QMenu类型的菜单显示需要调用的 API
// 参数 p 就是右键菜单需要显示的位置, 这个坐标需要使用屏幕坐标
// 该位置坐标一般通过调用 QCursor::pos() 直接就可以得到了
QAction *QMenu::exec(const QPoint &p, QAction *action = nullptr);
demo
在头文件中,添加 mousePressEvent 函数的声明
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
protected:
// 鼠标按下, 该函数被Qt框架调用, 需要重写该函数
void mousePressEvent(QMouseEvent *event);
};
#endif // MAINWINDOW_H
在对应的cpp中,添加 mousePressEvent 函数的定义
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QIcon"
#include "QTextEdit"
#include "QMessageBox"
#include "QMouseEvent"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 创建图标对象
QIcon Q(":/new/prefix1/img/a.png");
// QWidget类的 公共成员函数
this->setWindowIcon(Q);
// 给窗口设置图标
// 弊端: 发布的 exe 必须要加载 d:\\pic\\1.ico 如果当前主机对应的目录中没有图片, 图标就无法被加载
// 发布 exe 需要额外发布图片, 将其部署到某个目录中
//setWindowIcon(QIcon("d:\\pic\\1.ico"));
//使用API布局
// 创建符窗口对象
//QWidget *window1 = new QWidget();
// 创建若干个子窗口对象
QPushButton *button1 = new QPushButton("One");
QPushButton *button2 = new QPushButton("Two");
QPushButton *button3 = new QPushButton("Three");
QPushButton *button4 = new QPushButton("Four");
QPushButton *button5 = new QPushButton("Five");
// 创建水平布局对象
QHBoxLayout *layout1 = new QHBoxLayout;
// 将子窗口添加到布局中
layout1->addWidget(button1);
layout1->addWidget(button2);
layout1->addWidget(button3);
layout1->addWidget(button4);
layout1->addWidget(button5);
// 将水平布局设置给父窗口对象
this->ui->widget_3->setLayout(layout1);
// 显示父窗口
this->ui->widget_3->show();
//使用API布局
//创建垂直布局
// 创建符窗口对象
//QWidget *window2 = new QWidget;
// 创建若干个子窗口对象
QPushButton *button21 = new QPushButton("One");
QPushButton *button22 = new QPushButton("Two");
QPushButton *button23 = new QPushButton("Three");
QPushButton *button24 = new QPushButton("Four");
QPushButton *button25 = new QPushButton("Five");
// 创建垂直布局对象
QVBoxLayout *layout2 = new QVBoxLayout;
// 将子窗口添加到布局中
layout2->addWidget(button21);
layout2->addWidget(button22);
layout2->addWidget(button23);
layout2->addWidget(button24);
layout2->addWidget(button25);
// 将水平布局设置给父窗口对象
this->ui->widget_4->setLayout(layout2);
// 显示父窗口
this->ui->widget_4->show();
//使用API布局
//创建网格布局
// 创建父窗口对象
//QWidget* window3 = new QWidget;
// 创建子窗口对象
QPushButton *button31 = new QPushButton("One");
QPushButton *button32 = new QPushButton("Two");
QPushButton *button33 = new QPushButton("Three");
QPushButton *button34 = new QPushButton("Four");
QPushButton *button35 = new QPushButton("Five");
QPushButton *button6 = new QPushButton("Six");
// 多行文本编辑框
QTextEdit* txedit3 = new QTextEdit;
txedit3->setText("我占用了两行两列的空间哦。");
QGridLayout* layout = new QGridLayout;
// 按钮起始位置: 第1行, 第1列, 该按钮占用空间情况为1行1列
layout->addWidget(button1, 0, 0);
// 按钮起始位置: 第1行, 第2列, 该按钮占用空间情况为1行1列
layout->addWidget(button2, 0, 1);
// 按钮起始位置: 第1行, 第3列, 该按钮占用空间情况为1行1列
layout->addWidget(button3, 0, 2);
// 编辑框起始位置: 第2行, 第1列, 该按钮占用空间情况为2行2列
layout->addWidget(txedit3, 1, 0, 2, 2);
// 按钮起始位置: 第2行, 第3列, 该按钮占用空间情况为1行1列
layout->addWidget(button4, 1, 2);
// 按钮起始位置: 第3行, 第3列, 该按钮占用空间情况为1行1列
layout->addWidget(button5, 2, 2);
// 按钮起始位置: 第4行, 第1列, 该按钮占用空间情况为1行3列
layout->addWidget(button6, 3, 0, 1, 3);
// 网格布局设置给父窗口对象
this->ui->widget_5->setLayout(layout);
// 显示父窗口
this->ui->widget_5->show();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::mousePressEvent(QMouseEvent *event){
// 判断用户按下的是哪一个鼠标键
if(event->button() == Qt::RightButton)
{
// 弹出一个菜单, 菜单项是 QAction 类型
QMenu menu;
QAction* act = menu.addAction("C++");
connect(act, &QAction::triggered, this, [=]()
{
QMessageBox::information(this, "title", "您选择的是C++...");
});
menu.addAction("Java");
menu.addAction("Python");
menu.exec(QCursor::pos()); // 右键菜单被模态显示出来了
}
}
效果
我稍作修改,添加左击和右击的效果:
void MainWindow::mousePressEvent(QMouseEvent *event){
// 判断用户按下的是哪一个鼠标键
if(event->button() == Qt::RightButton)
{
// 弹出一个菜单, 菜单项是 QAction 类型
QMenu menu;
QAction* act1 = menu.addAction("C++");
connect(act1, &QAction::triggered, this, [=]()
{
QMessageBox::information(this, "title", "您选择的是C++...");
});
QAction* act2 =menu.addAction("Java");
connect(act2, &QAction::triggered, this, [=]()
{
QMessageBox::information(this, "title", "您选择的是JAVA...");
});
QAction* act3 =menu.addAction("Python");
connect(act3, &QAction::triggered, this, [=]()
{
QMessageBox::information(this, "title", "您选择的是PYthon...");
});
menu.exec(QCursor::pos()); // 右键菜单被模态显示出来了
}
if(event->button() == Qt::LeftButton)
{
// 弹出一个菜单, 菜单项是 QAction 类型
QMenu menu;
QAction* act = menu.addAction("hello");
connect(act, &QAction::triggered, this, [=]()
{
QMessageBox::information(this, "title", "您使用鼠标左键点击了一下");
});
menu.exec(QCursor::pos()); // 右键菜单被模态显示出来了
}
}
基于窗口的菜单策略实现
这种方式是使用 Qt 中 QWidget类中的右键菜单函数 QWidget::setContextMenuPolicy(Qt::ContextMenuPolicy policy) 来实现
API如下:
// 函数原型:
void QWidget::setContextMenuPolicy(Qt::ContextMenuPolicy policy);
参数:
- Qt::NoContextMenu --> 不能实现右键菜单
- Qt::PreventContextMenu --> 不能实现右键菜单
- Qt::DefaultContextMenu --> 基于事件处理器函数 QWidget::contextMenuEvent() 实现
- Qt::ActionsContextMenu --> 添加到当前窗口中所有 QAction 都会作为右键菜单项显示出来
- Qt::CustomContextMenu --> 基于 QWidget::customContextMenuRequested() 信号实现
Qt::DefaultContextMenu
第一步:在相应的窗口的类的头文件中添加这个函数 QWidget::contextMenuEvent() 的声明
第二步在这个窗口类的构造函数设置右键菜单策略
第三步在这个窗口类的源文件中重写事件处理器函数 contextMenuEvent()
Qt::ActionsContextMenu
使用这个策略实现右键菜单, 是最简单的一种, 我们只需要创建一些 QAction类型的对象并且将他们添加到当前的窗口中, 当我们在窗口中点击鼠标右键这些QAction类型的菜单项就可以显示出来了。
Qmainwindow的调用代码:
在mydialog2中:
#include "mydialog2.h"
#include "ui_mydialog2.h"
#include "QAction"
#include "QMessageBox"
myDialog2::myDialog2(QWidget *parent) :
QDialog(parent),
ui(new Ui::myDialog2)
{
ui->setupUi(this);
// 只要将某个QAction添加给对应的窗口, 这个action就是这个窗口右键菜单中的一个菜单项了
// 在窗口中点击鼠标右键, 就可以显示这个菜单
setContextMenuPolicy(Qt::ActionsContextMenu);
// 给当前窗口添加QAction对象
QAction* act1 = new QAction("C++");
QAction* act2 = new QAction("Java");
QAction* act3 = new QAction("Python");
this->addAction(act1);
this->addAction(act2);
this->addAction(act3);
connect(act1, &QAction::triggered, this, [=]()
{
QMessageBox::information(this, "title", "您选择的是C++...");
});
}
myDialog2::~myDialog2()
{
delete ui;
}
Qt::CustomContextMenu
使用这个策略实现右键菜单, 当点击鼠标右键,窗口会产生一个 QWidget::customContextMenuRequested() 信号,注意仅仅只是发射信号,意味着要自己写显示右键菜单的槽函数(slot),这个信号是QWidget唯一与右键菜单有关的信号。
信号API
// 注意: 信号中的参数pos为当前窗口的坐标,并非屏幕坐标,右键菜单显示需要使用屏幕坐标
[signal] void QWidget::customContextMenuRequested(const QPoint &pos)
#include "mydialog3.h"
#include "ui_mydialog3.h"
#include "QMenu"
#include "QMessageBox"
myDialog3::myDialog3(QWidget *parent) :
QDialog(parent),
ui(new Ui::myDialog3)
{
ui->setupUi(this);
// 策略 Qt::CustomContextMenu
// 当在窗口中点击鼠标右键, 窗口会发出一个信号: QWidget::customContextMenuRequested()
// 对应发射出的这个信号, 需要添加一个槽函数, 用来显示右键菜单
this->setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, &QDialog::customContextMenuRequested, this, [=](const QPoint &pos)
{
// 参数 pos 是鼠标按下的位置, 但是不能直接使用, 这个坐标不是屏幕坐标, 是当前窗口的坐标
// 如果要使用这个坐标需要将其转换为屏幕坐标
QMenu menu;
QAction* act = menu.addAction("C++");
connect(act, &QAction::triggered, this, [=]()
{
QMessageBox::information(this, "title", "您选择的是C++...");
});
QAction* act2 = menu.addAction("Java");
connect(act2, &QAction::triggered, this, [=]()
{
QMessageBox::information(this, "title", "您选择的是加瓦");
});
menu.addAction("Python");
// menu.exec(QCursor::pos());
// 将窗口坐标转换为屏幕坐标
QPoint newpt = this->mapToGlobal(pos);
menu.exec(newpt);
});
}
myDialog3::~myDialog3()
{
delete ui;
}