【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…

Go语言中工作负载类型对并发的影响

在实际工作开发中我们需要根据工作负载是CPU密集型还是I/O密集型,使用不同的方式来解决问题。下面我们先来看这些概念,然后再讨论其影响。 在程序执行时,工作负载的执行时间会受以下因素限制: CPU的速度--例如,运行归并排序算法。工作负载被称为CPU密集型。I/O速度--例如…

Ubuntu 点击图标窗口最小化

本文所使用的 Ubuntu 系统版本是 Ubuntu 22.04 ! 用过 Ubuntu 系统的都知道&#xff0c;点击任务栏上的图标&#xff0c;它只能打开应用&#xff0c;而不能最小化应用。我希望点击图标能让窗口最小化这种效果&#xff0c;那该如何做呢&#xff1f; # 打开终端&#xff0c;输入如…

Docker-Compose配置文件docker-compose.yml详解

一份标准的docker-compose.yml文件应该包含version、services、networks三大部分&#xff0c;其中最关键的就是services和networks两个部分。 Compose和Docker兼容性&#xff1a; Compose 文件格式有3个版本,分别为1, 2.x 和 3.x 目前主流的为 3.x 其支持 docker 1.13.0 及其以…

C++---vector容器

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

C++ 二重指针

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

无线通信:调制(Modulation)方式

什么是调制方式 调制方式就是将信源信息&#xff08;要传输的信息&#xff09;加载到载波波形上&#xff0c;通过改变载波的某些特性来代表这些信息。通常&#xff0c;传统模拟信号有三种最基本的调制方式&#xff1a;改变幅度的叫调幅&#xff08;AM&#xff09;&#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;…

Google的代码审查准则

Google的代码审查准则&#xff1a;持续优化与分享知识 在Google的软件开发流程中&#xff0c;代码审查扮演着举足轻重的角色。这一环节不仅保证了代码的质量&#xff0c;更是知识传承和经验共享的重要途径。接下来&#xff0c;我们就来深入探讨Google代码审查的几大准则。 一…

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

使用腾讯云服务器搭建网站全流程&#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;可能看起来对区块链创新持守旧态度。一家初创公司认为现在是时候改…

【PX4仿真】使用PX4+Gazebo+MAVROS+ROS进行无人机仿真中提高IMU消息频率的方法

在无人机仿真中&#xff0c;IMU&#xff08;惯性测量单元&#xff09;消息频率对于路径规划和感知的仿真至关重要。然而&#xff0c;在使用PX4GazeboMAVROSROS进行仿真时&#xff0c;可能会遇到频率受限的情况。本文将介绍如何提高IMU消息频率。 通过以下命令可以查看到IMU消息…