在Qt窗口中添加右键菜单

基于鼠标的事件实现

流程

需要使用:事件处理器函数(回调函数)

  1. 在当前窗口类中重写鼠标操作相关的的事件处理器函数,有两个可以选择
// 以下两个事件二选一即可, 只是事件函数被调用的时机不同罢了
// 这个时机对右键菜单的显示没有任何影响
[virtual protected] void QWidget::mousePressEvent(QMouseEvent *event);
[virtual protected] void QWidget::mouseReleaseEvent(QMouseEvent *event);
  1. 在数据表事件处理器函数内部判断是否按下了鼠标右键
  2. 如果按下了鼠标右键创建菜单对象(也可以提前先创建处理), 并将其显示出来
// 关于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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值