功能描述:需要在QOpenGLWidget窗口内动态创建一个QPushButton,当鼠标滑过QPushButton时,弹出QPushButton下面的QMenu,选择QMenu内的QAction执行相应的功能。
问题分析:QPushButton 默认操作是点击按钮弹出QMenu;如果要通过鼠标滑过按钮触发弹出QMenu,则要在QPushButton的基础上派生出自己的PushButton来处理滑动事件。
#pragma once
#include <QPushButton>
class CustomPushButton : public QPushButton
{
Q_OBJECT
public:
CustomPushButton(QWidget *parent = Q_NULLPTR);
~CustomPushButton();
private:
void mouseMoveEvent(QMouseEvent *event); // 鼠标移动事件
};
#include "CustomPushButton.h"
#include <QMenu>
#include <QAction>
#include <QMouseEvent>
CustomPushButton::CustomPushButton(QWidget *parent)
: QPushButton(parent)
{
}
CustomPushButton::~CustomPushButton()
{
}
void CustomPushButton::mouseMoveEvent(QMouseEvent *event)
{
const QRect customBtnRect = this->geometry();
const QPoint mousePos = event->pos() + customBtnRect.topLeft();
if (customBtnRect.contains(mousePos))
{
if (this->menu())
{
this->menu()->popup(this->mapToGlobal(QPoint(0, 0)));
}
}
}
自己的PushButton派生类写好了之后,在QOpenGLWidget类头文件中定义该PushButton派生类和QMenu。
CustomPushButton *m_btnMenu;
QMenu *m_menu;
在QOpenGLWidget类cpp文件中实现m_btnMenu和m_menu的初始化。
void OpenglWidget::initializeGL()
{
QAction *act1 = new QAction(this);
QAction *act2 = new QAction(this);
m_menu = new QMenu(this);
//m_menu->installEventFilter(this);
m_menu->setMouseTracking(true);
m_menu->addAction(act1);
m_menu->addAction(act2);
m_btnMenu = new CustomPushButton(this);
m_btnMenu->setFixedSize(QSize(30, 30));
m_btnMenu->setIconSize(QSize(30, 30));
m_btnMenu->setIcon(QIcon(QString("*.png")));
m_btnMenu->move(QPoint(10, 10));
m_btnMenu->setMenu(m_menu);
m_btnMenu->setMouseTracking(true);
}
实现了上述步骤运行后正常就能看到窗口中有一个按钮,鼠标滑过按钮时会弹出定义好的菜单,但是鼠标滑出菜单,菜单不会消失。下面通过Qt eventFilter来解决该问题。Qt eventFilter的使用有2个函数:一个是 installEventFilter负责在相应部件上安装事件过滤器;另一个函数是 eventFilter 函数,我们在此函数中实现事件过滤器。
在QMenu定义中安装eventFilter。
m_menu = new QMenu(this);
m_menu->installEventFilter(this);
m_menu->setMouseTracking(true);
m_menu->addAction(act1);
m_menu->addAction(act2);
bool OpenglWidget::eventFilter(QObject *watched, QEvent * event)
{
if (watched == m_menu)
{
if (event->type() == QEvent::MouseMove)
{
QPointF lp = ((QMouseEvent*)event)->localPos();
const auto& actionSize = m_menu->actions().size();
bool flag = false;
for (size_t i = 0; i < actionSize; ++i)
{
QRect rc = m_menu->actionGeometry(m_menu->actions()[i]);
if (rc.contains(lp.toPoint()))
{
// 鼠标滑动选中action时,更改该action的icon...
flag = true;
}
else
{
// 鼠标滑出action时,更改该action的icon...
}
}
if (!flag)
m_menu->hide();
}
}
return false;
}
这个问题困扰了我几天,写下该博客是为记录,并分享给需要的人。