【QT入门】 Qt自定义控件与样式设计之QPushButton实现鼠标悬浮按钮弹出对话框

往期回顾:

【QT入门】 Qt自定义控件与样式设计之qss选择器-CSDN博客

【QT入门】 Qt自定义控件与样式设计之QLineEdit的qss使用-CSDN博客

【QT入门】Qt自定义控件与样式设计之QPushButton常用qss-CSDN博客

【QT入门】 Qt自定义控件与样式设计之QPushButton实现鼠标悬浮按钮弹出对话框

一、最终效果

鼠标悬浮弹出对话框的功能:最终要实现纯代码设计出一个音量按钮,当鼠标悬浮在上面的时候,显示滑块,并可以自己调节大小,鼠标离开后滑块消失。

二、具体实现

 1、鼠标事件捕捉

首先实现一个基本功能,就是窗口能识别鼠标,鼠标放上去就显示,不放上去就不显示,这个功能很简单只需要重写两个函数

void enterEvent(QEvent * event) override;
void leaveEvent(QEvent * event) override;

在Widget主窗口写这两个类,你那么就能实现鼠标放进主窗口有反应,拿出来也有反应

void Widget::enterEvent(QEvent * event)
{qDebug()<<"11111";
}void Widget::leaveEvent(QEvent * event)
{qDebug()<<"22222";
}

2、加载主布局 

Widget类加载主布局,主类没操作,就是设置大小,创建布局,把按钮放进去。

Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);resize(800, 600);//创建水平布局QHBoxLayout *pHlay = new QHBoxLayout(this);//创建音量按钮并添加到布局水平布局里CVolumeButton* pVolumeButton = new CVolumeButton(this);pHlay->addWidget(pVolumeButton);
}

3、创建滑块 

 3.1cvolumesliderdialog类创建滑块

这个类本身继承自QDialog,主要作用是创建QSlider对象并添加到布局中。

QSlider是用于控制边界值的经典小部件。它允许用户沿水平或垂直凹槽移动QSlider 的滑块,并将 滑块 的位置转换为合法范围内的整数值。

    //设置对话框的固定大小为(40, 200)this->setFixedSize(40, 200);//创建一个垂直布局管理器pVLay,QVBoxLayout* pVLay = new QVBoxLayout(this);m_pSlider = new QSlider(this);//将一个垂直方向的QSlider对象m_pSlider添加到布局中m_pSlider->setOrientation(Qt::Vertical);pVLay->addWidget(m_pSlider);
3.2设置窗口标志

另外比较重要的一点,把设置窗口标志为无边框窗口和ToolTip提示框样式

这里用到一个ToolTip,ToolTip = Popup | Sheet ,可以实现滑块悬浮时显示,离开时消失

setFixedSize(40, 120);//设置窗口标志为无边框窗口和ToolTip提示框样式//ToolTip = Popup | Sheet,setWindowFlags(Qt::FramelessWindowHint | Qt::ToolTip);   //ToolTip : 悬浮时显示,离开时消失setStyleSheet("QDialog{background-color: rgba(54, 54, 54, 0.5);}");  //0.5表示透明度,0表示全透明、1表示不透明;
//也可以使用百分百表示如: frm->setStyleSheet(“QFrame{background-color: rgba(255, 0, 0, 50%);}”);
3.3修复bug

bug: bool QWidget::event(QEvent *event)这个方法设置popup后,dialog会有窗口阴影

需要去除就重写event函数,

bool CVolumeSliderDialog::event(QEvent* event)
{//定义一个静态布尔变量class_amended,用于跟踪是否已经修改了窗口类。static bool class_amended = false;//事件类型为WinIdChange,表示窗口标识已更改。if (event->type() == QEvent::WinIdChange){//获取对话框的窗口句柄HWND hwnd = (HWND)winId();//检查是否已经修改了窗口类if (class_amended == false){class_amended = true;//将class_amended设置为true,表示已经修改了窗口类DWORD class_style = ::GetClassLong(hwnd, GCL_STYLE);//获取窗口类的样式//将CS_DROPSHADOW样式从窗口类样式中移除,这样可以去除窗口阴影class_style &= ~CS_DROPSHADOW;//将修改后的窗口类样式应用到窗口::SetClassLong(hwnd, GCL_STYLE, class_style); // windows系统函数}}//调用基类QWidget的event函数来处理事件,确保其他事件得到正常处理return QWidget::event(event);
}

注意这个完全可以作为一个通用类,需要的时候直接使用。

4、创建音量按钮

cvolumebutton类实现音量按钮的创建和滑块的绑定以及逻辑实现

主要是几个逻辑实现
 

1、纯代码创建一个音量按钮
2、创建滑块并定位在按钮上方合适位置
3、判断是否点击按钮需要静音来改变滑块上的位置
4、通过定时器判断鼠标是否离开按钮和滑块区域,离开滑块就消失
4.1首先通过重写paintEvent方法,实现了在CVolumeButton控件上绘制一个按钮外观的功能 
//代码可重用
void CVolumeButton::paintEvent(QPaintEvent*)
{//QStylePainter用于绘制基于QStyle的外观元素QStylePainter p(this);//QStyleOptionButton用于存储按钮控件的外观选项,如颜色、边框等QStyleOptionButton option;//调用initStyleOption方法初始化option对象//initStyleOption通常用于设置控件的外观选项,以便正确绘制控件initStyleOption(&option);//使用QStylePainter对象p绘制一个CE_PushButton类型的控件,参数为option对象。//这将根据option中的外观选项绘制按钮的外观,如背景、文本等p.drawControl(QStyle::CE_PushButton, option);
}
4.2然后在鼠标进入声音按钮时,创建并显示一个音量滑块对象,将其定位在合适的位置,并启动一个定时器。同时,建立了一个信号与槽的连接,以便在滑块数值变化时通知其他部分。 
void CVolumeButton::enterEvent(QEvent* event)
{//判断并初始化滑块对象,确保只有在需要时才创建滑块对象if (!m_pVolumeSliderDlg)m_pVolumeSliderDlg = new CVolumeSliderDialog(this);QPoint p1 = this->mapToGlobal(QPoint(0, 0));  //声音按钮左上角相对于桌面的绝对位置QRect rect1 = this->rect();    //获取声音按钮的矩形区域//获取滑块对象的矩形区域,rect包含标题栏,去掉标题栏后height不变QRect rect2 = m_pVolumeSliderDlg->rect();//计算滑块对象在水平方向上的位置,使其水平居中于声音按钮//这里计算很简单,就是按钮的一半减去滑块的一半,就是多出来的那部分//按钮的x加上多出来那部分,就能得到滑块居中的x位置int x = p1.x() + (rect1.width() - rect2.width()) / 2;//计算滑块对象在垂直方向上的位置,使其位于声音按钮上方并略微偏移5px//按钮的y减去滑块的长度再减去偏移的5px,就是滑块的左上角y位置int y = p1.y() - rect2.height() - 5;//滑块对象移动到计算得到的位置m_pVolumeSliderDlg->move(x, y);   //move是相对于桌面原点的位置m_pVolumeSliderDlg->show();//显示滑块对象m_timerId = startTimer(250);//动一个定时器,每250毫秒触发一次定时器事件connect(m_pVolumeSliderDlg, &CVolumeSliderDialog::sig_SliderValueChanged, [=](int value) {emit sig_VolumeValue(value);});
}
4.3检测鼠标按下事件实现静音
void CVolumeButton::mousePressEvent(QMouseEvent* event)
{if (event->button() == Qt::LeftButton)//检查鼠标按下的按钮是否是左键{m_isMute = !m_isMute; //切换静音状态,真假切换if (m_isMute)//如果当前为静音状态{//如果滑块对象存在,将滑块值设置为0,表示静音状态if (m_pVolumeSliderDlg)m_pVolumeSliderDlg->setSliderValue(0);}else{//如果滑块对象存在,将滑块值设置为50,表示非静音状态下的默认音量if (m_pVolumeSliderDlg)m_pVolumeSliderDlg->setSliderValue(50);}}
}
4.4在定时器事件中检测鼠标位置,如果鼠标移出音量滑块对象或声音按钮的区域,则隐藏音量滑块对象;如果音量滑块对象不存在或不可见,则停止定时器。
void CVolumeButton::timerEvent(QTimerEvent* event)
{//检查音量滑块对象是否存在且可见if ((m_pVolumeSliderDlg != nullptr) && (m_pVolumeSliderDlg->isVisible())){QPoint p1 = QCursor::pos();   //鼠标绝对位置if (m_pVolumeSliderDlg){QRect rect1 = this->rect();  //获取声音按钮的矩形区域QRect rect2 = m_pVolumeSliderDlg->rect();//获取音量滑块对象的矩形区域QRect rect3 = m_pVolumeSliderDlg->geometry();//获取音量滑块对象的几何信息QPoint p2 = this->mapToGlobal(QPoint(0, 0));   //声音按钮左上角相对于桌面的绝对位置//已知:音量框宽40 > 按钮宽30//创建一个矩形区域,用于检测鼠标位置是否在音量滑块对象或声音按钮上QRect area(rect3.left(), rect3.top(), rect2.width(), p2.y() + rect1.height() - rect3.top()); //左上宽高if (!area.contains(p1))//如果鼠标位置不在矩形区域内{m_pVolumeSliderDlg->hide();//隐藏音量滑块对象}}}else //如果鼠标位置在矩形区域内{//停止定时器,即终止定时器事件的触发killTimer(m_timerId);}
}

都看到这里了,点个赞再走呗朋友~

加油吧,预祝大家变得更强!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/813524.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

scipy.signal.cwt 与 pywt.cwt 使用记录

scipy.signal.cwt 该代码中widths以及freq计算公式来源于scipy.signal.morlet2函数官方案例 from scipy.signal import morlet, morlet2 from scipy import signal import matplotlib.pyplot as pltsignal_length 2000 fs 1000# 生成信号数据 time np.arange(0, signal_leng…

黄仁勋揭秘EIOFS(未来成功早期指标)英伟达成为最伟大AI企业的核心奥义

黄仁勋揭秘EIOFS(未来成功早期指标&#xff09;英伟达成为最伟大AI企业的核心奥义 原创 AI 吴厂长 AI 吴厂长 2024-04-02 00:12 上海 黄仁勋&#xff1a;你应该寻找未来成功的早期指标&#xff0c;而且越早越好。 原因是你想尽早看到自己正走在正确的方向上。 有个短语叫EIO…

C++---vector容器

是STL容器中的一种常用的容器&#xff0c;由于其大小(size)可变&#xff0c;常用于数组大小不可知的情况下来替代数组。vector容器与数组十分相似&#xff0c;被称为动态数组。时间复杂度为O&#xff08;1&#xff09;。 数组数据通常存储在栈中&#xff0c;vector数据通常存储…

C++ 二重指针

一 指向指针的指针 如果在一个指针变量中存放的是另一个变量的指针的地址&#xff0c;称该指针为指向指针的指针&#xff0c;即二重指针。

2.1 LeetCode总结(基本算法)_DFS

1.4 练习 104. 二叉树的最大深度 int maxDepth(struct TreeNode *root, int len) {if (root NULL) {return len;}return fmax(maxDepth(root->left, len1), maxDepth(root->right, len1)); }二叉树最大深度就是基本的递归思路的求解&#xff0c; 手法主要是递归下去之…

C语言基础(三)

C语言基础 三大结构顺序结构选择结构单分支选择结构双分支选择结构多分支选择结构if ...else if....elseswitch语句 循坏结构for循环表达式1可以省略吗&#xff1f;表达式2可以省略吗&#xff1f;表达式3可以省略吗&#xff1f;for循坏的嵌套 while循环do while循坏while与do w…

android支付宝接入流程

接入前准备 接入APP支付能力前&#xff0c;开发者需要完成以下前置步骤。 本文档展示了如何从零开始&#xff0c;使用支付宝开放平台服务端 SDK 快速接入App支付产品&#xff0c;完成与支付宝对接的部分。 第一步&#xff1a;创建应用并获取APPID 要在您的应用中接入支付宝…

【新版】系统架构设计师 - 知识点 - 结构化开发方法

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 文章目录 架构 - 知识点 - 结构化开发方法结构化开发方法结构化分析结构化设计 数据流图和数据字典模块内聚类型与耦合类型 架构 - 知识点 - 结构化开发方法 结构化开发方法 分析阶段 工具&#xff1a;数据流图、…

前端学习<四>JavaScript基础——20-函数简介

函数的介绍 函数&#xff1a;就是一些功能或语句的封装。在需要的时候&#xff0c;通过调用的形式&#xff0c;执行这些语句。 补充&#xff1a; 函数也是一个对象 使用typeof检查一个函数对象时&#xff0c;会返回 function 函数的作用&#xff1a; 一次定义&#xff0c;…

腾讯云服务器搭建网站教程,新手跟着流程一步步操作

使用腾讯云服务器搭建网站全流程&#xff0c;包括轻量应用服务器和云服务器CVM建站教程&#xff0c;轻量可以使用应用镜像一键建站&#xff0c;云服务器CVM可以通过安装宝塔面板的方式来搭建网站&#xff0c;腾讯云服务器网txyfwq.com整理使用腾讯云服务器建站教程&#xff0c;…

《黑马点评》Redis高并发项目实战笔记(上)P1~P45

P1 Redis企业实战课程介绍 P2 短信登录 导入黑马点评项目 首先在数据库连接下新建一个数据库hmdp&#xff0c;然后右键hmdp下的表&#xff0c;选择运行SQL文件&#xff0c;然后指定运行文件hmdp.sql即可&#xff08;建议MySQL的版本在5.7及以上&#xff09;&#xff1a; 下面这…

Ubuntu20.04安装ROS过程记录以及常见报错处理

官网安装步骤如下&#xff1a; http://wiki.ros.org/cn/noetic/Installation/Ubuntu#A.2BXwBZy1uJiMU- 第一个&#xff1a;添加ROS软件源 sudo sh -c echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-la…

2024年mathorcup数学建模C题思路分析-物流网络分拣中心货量预测及人员排班

# 1 赛题 C 题 物流网络分拣中心货量预测及人员排班 电商物流网络在订单履约中由多个环节组成&#xff0c;图 ’ 是一个简化的物流 网络示意图。其中&#xff0c;分拣中心作为网络的中间环节&#xff0c;需要将包裹按照不同 流向进行分拣并发往下一个场地&#xff0c;最终使包裹…

Quantum Temple借助Sui通过NFT推动再生旅游

从金融到艺术&#xff0c;从游戏到无线网络&#xff0c;各行各业都涌现出大量初创公司&#xff0c;利用区块链技术颠覆现状。说到旅游业&#xff0c;让人联想到拥挤的机场、快节奏的旅游和豪华游轮&#xff0c;可能看起来对区块链创新持守旧态度。一家初创公司认为现在是时候改…

【神经网络与深度学习】循环神经网络基础

tokenization tokenization&#xff1a;分词 每一个词语都是token 分词方法&#xff1a;转为单个词、转为多个词语 N-gram表示法 准备词语特征的方法 &#xff08;把连续的N个词作为特征&#xff09; 如 ”我爱你“——>[我&#xff0c;爱&#xff0c;你] 2-gram——[[我…

MySQL 嵌套查询

嵌套查询 是指在一个完整的查询语句之中&#xff0c;包含若干个不同功能的小查询&#xff1b;从而一起完成复杂查询的一种编写形式。包含的查询放在&#xff08;&#xff09;里 &#xff0c; 包含的查询出现的位置&#xff1a; 位置含义SELECT之后把查询结果作为表头使用FROM…

Redis中的集群(九)

集群 消息 集群中的各个节点通过发送和接收消息(message)来进行通信&#xff0c;我们称发送消息的节点为发送者(sender),接收消息 的节点成为接收者&#xff0c;如图所示。节点发送的消息主要有以下五种: 1.MEET消息:当发送者接到客户端发送的CLUSTER MEET命令时&#xff0c…

LabVIEW电信号傅里叶分解合成实验

LabVIEW电信号傅里叶分解合成实验 电信号的分析与处理在科研和工业领域中起着越来越重要的作用。系统以LabVIEW软件为基础&#xff0c;开发了一个集电信号的傅里叶分解、合成、频率响应及频谱分析功能于一体的虚拟仿真实验系统。系统不仅能够模拟实际电路实验箱的全部功能&…

ExpressLRS硬件实测性能分析

ExpressLRS硬件实测性能分析 1. 源由2. 远航测试3. 实验室测试3.1 芯片RSSI与实测功率差异3.2 SNR信噪比稳定3.3 140db衰减器衰减&#xff0c;40个频点信号稳定 4. 外场测试4.1 无屏蔽样品4.2 有屏蔽样品4.3 有屏蔽vs无屏蔽样品 5. 估算6. 总结7. 补充说明 -- 50mW视频 1. 源由…

降额的秘密——不要挑战datasheet!

原文来自微信公众号&#xff1a;工程师看海&#xff0c;与我联系&#xff1a;chunhou0820 看海原创视频教程&#xff1a;《运放秘籍》 大家好&#xff0c;我是工程师看海。 什么是降额设计&#xff1f;我们为什么要降额&#xff1f; 额指的是额定工作状态&#xff0c;降额就是…