当前位置: 首页 > news >正文

【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);}
}

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

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

相关文章:

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

往期回顾&#xff1a; 【QT入门】 Qt自定义控件与样式设计之qss选择器-CSDN博客 【QT入门】 Qt自定义控件与样式设计之QLineEdit的qss使用-CSDN博客 【QT入门】Qt自定义控件与样式设计之QPushButton常用qss-CSDN博客 【QT入门】 Qt自定义控件与样式设计之QPushButton实现鼠标悬…...

C盘变红怎么办?免费的系统C盘清理方法,C盘空间占用克星

百夫说&#xff1a;分享免费又好用的工具&#xff0c;是一件快乐的事情。 正文&#xff1a; 起因&#xff1a;C盘报警&#xff0c;系统变慢 立即下载XX系统清理大师&#xff0c;搜索出垃圾数据近30G&#xff0c;开心的点击“一键清理”&#xff0c;结果提示要收费&#xff1a…...

简述VPS 与 Apache 搭建网站方式对比:新手科普指南

在互联网时代&#xff0c;拥有一个网站对于个人、企业以及组织来说已经成为了必备的一项资源。然而&#xff0c;对于新手来说&#xff0c;如何搭建一个网站可能是一个挑战。在这篇文章中&#xff0c;我将探讨两种常见的搭建网站的方式&#xff1a;使用虚拟专用服务器&#xff0…...

js获取年月份

一、date 如何使用、如何获取年月日时分秒、时间戳、如何获取指定日期的时间戳或周几 1..Date 对象用于处理日期和时间。 创建 Date 对象的语法&#xff1a; var myDatenew Date() 获取年月日时分秒&#xff1a; // 格式化日对象 const getNowDate () > {let date new …...

Promise常用方法及区别

一、实例方法 let _fun new Promise((resolve, reject) > {reject("失败&#xff01;"); }); /* resolve&#xff1a;异步操作成功时调用的回调函数。 reject&#xff1a;异步操作失败时调用的回调函数。 */ _fun.then(res > { // 成功console.log(res: , re…...

pyqt 标题栏设置

在PyQt中&#xff0c;可以通过QWidget或其子类&#xff08;如QMainWindow或QDialog&#xff09;的setWindowTitle()方法来设置窗口的标题栏。以下是一个简单的例子&#xff0c;展示了如何为应用程序的主窗口设置标题&#xff1a; import sys from PyQt5.QtWidgets import QApp…...

关于可视化大屏适配

一、目前市场上适配方案有两种&#xff1b; vw、vh方案&#xff1a; 原理&#xff1a;按照设计稿的尺寸&#xff0c;将px按比例计算转为vw和vh&#xff1b; 优点&#xff1a;不会存在失真情况、可以动态计算图表的宽高&#xff0c;字体等&#xff0c;灵活性较高&#xff0c;…...

如何用composer来安装和配置LAMP环境?

LAMP环境是一个开发和运行Web应用程序的常见环境&#xff0c;它由Linux、Apache、MySQL和PHP组成。Composer是一个用于管理PHP依赖关系的工具&#xff0c;可以方便地安装和配置LAMP环境中的各种软件包。下面是使用Composer安装和配置LAMP环境的步骤&#xff1a; 安装Composer&a…...

题目:学习使用按位取反~。

题目&#xff1a;学习使用按位取反~。  There is no nutrition in the blog content. After reading it, you will not only suffer from malnutrition, but also impotence. The blog content is all parallel goods. Those who are worried about being cheated should leav…...

vue3第十六节(keep-alive 内置组件)

keep-alive 1、目的 在使用组件时&#xff0c;有时我们需要将组件进行缓存&#xff0c;而不是重新渲染&#xff0c;用以提高性能&#xff0c;避免重复加载DOM&#xff0c;提升用户的体验&#xff1b; keep-alive 组件可以做到这一点&#xff0c;它允许你缓存组件实例&#xf…...

跨域和跨域解决方案

跨域 制定HTML规则时&#xff0c;出于安全的考虑&#xff0c;一个源的网站不允许与另一个源的资源进行交互&#xff0c;浏览器制定此规则为同源策略。 同源即指的网站具有相同的域&#xff0c;即 协议(protocol)、主机(host)、端口号(port) 相同。 跨域资源嵌入是允许的&am…...

数学基础:矩阵

来自: https://www.shuxuele.com/algebra/matrix-determinant.html 一、矩阵的行列式 二、矩阵简单知识 三、矩阵乘法 四、单位矩阵 五、逆矩阵一&#xff1a;简单2阶矩阵求法 六、逆矩阵二&#xff1a;3、4阶逆矩阵求法 6.1 求余子式矩阵 6.2 求代数余子式矩阵 6.3 求伴随矩阵…...

Windows完全卸载MySQL后再下载安装(附安装包)

目录 友情提醒第一章&#xff1a;如何完全卸载干净mysql教程&#xff08;三个步骤完全卸载&#xff09;1&#xff09;步骤一&#xff1a;卸载程序2&#xff09;步骤二&#xff1a;删除文件3&#xff09;步骤三&#xff1a;删除注册表信息 第二章&#xff1a;下载软件两种方式1&…...

【央国企专场】——国家电网

国家电网目录 一、电网介绍1、核心业务2、电网组成 二、公司待遇三、公司招聘1、招聘平台2、考试安排2.3 考试内容 一、电网介绍 1、核心业务 国家电网公司&#xff08;State Grid Corporation of China&#xff0c;简称SGCC&#xff09;是中国最大的国有企业之一&#xff0c…...

linux 安装MySQL

一、安装mysql 1. 先上传mysql的安装包 使用 rz上传图中的两个rpm包即可 上传的目录: /export/software 2. 卸载linux原生的mysql rpm -qa | grep mysql 如果能看到上图中的mysql-lib…,说明已经安装了&#xff0c;需将其卸载&#xff0c;如&#xff1a;…...

行云防水堡-打造企业数据安全新防线

企业数据安全&#xff0c;顾名思义就是通过各种手段或者技术或者工具保障企业数据的安全性&#xff1b;保障数据信息的硬件、软件及数据受到保护&#xff0c;不受偶然的或者恶意的原因而遭到破坏、更改、泄露&#xff0c;系统连续可靠正常地运行&#xff0c;信息服务不中断。目…...

在ORACLE中找出某列非数字类型的数据

在ORACLE中找出某列非数字类型的数据 使用正则表达式判断非数字值 在Oracle中&#xff0c;我们可以使用正则表达式来判断一个值是否为非数字。正则表达式提供了一种强大的模式匹配和搜索功能&#xff0c;通过匹配数字字符来判断是否为数字。以下是使用正则表达式判断非数字值的…...

建造者模式:构造复杂对象的艺术

在面向对象的设计中&#xff0c;建造者模式是一种重要的创建型设计模式&#xff0c;专门用来构建复杂的对象。它主要目的是将对象的构造代码与其表示代码分离&#xff0c;使同样的构建过程可以创建不同的表示。本文将详细介绍建造者模式的定义、实现、应用场景以及优缺点&#…...

Fence同步

在《Android图形显示系统》没有介绍到帧同步的相关概念&#xff0c;这里简单介绍补充一下。 在图形显示系统中&#xff0c;图形缓存GraphicBuffer可以被不同的硬件来访问&#xff0c;如CPU、GPU、HWC都可以对缓存进行读写&#xff0c;如果同时对图形缓存进行操作&#xff0c;有…...

【UE 委托】如何利用函数指针理解委托的基本原理

目录 0 引言1 函数指针模拟多播委托 &#x1f64b;‍♂️ 作者&#xff1a;海码007&#x1f4dc; 专栏&#xff1a;UE虚幻引擎专栏&#x1f4a5; 标题&#xff1a;【UE 委托】如何利用函数指针理解委托的基本原理❣️ 寄语&#xff1a;书到用时方恨少&#xff0c;事非经过不知难…...

19c补丁后oracle属主变化,导致不能识别磁盘组

补丁后服务器重启&#xff0c;数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后&#xff0c;存在与用户组权限相关的问题。具体表现为&#xff0c;Oracle 实例的运行用户&#xff08;oracle&#xff09;和集…...

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件

在选煤厂、化工厂、钢铁厂等过程生产型企业&#xff0c;其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进&#xff0c;需提前预防假检、错检、漏检&#xff0c;推动智慧生产运维系统数据的流动和现场赋能应用。同时&#xff0c;…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

HashMap中的put方法执行流程(流程图)

1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中&#xff0c;其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下&#xff1a; 初始判断与哈希计算&#xff1a; 首先&#xff0c;putVal 方法会检查当前的 table&#xff08;也就…...

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...

算法—栈系列

一&#xff1a;删除字符串中的所有相邻重复项 class Solution { public:string removeDuplicates(string s) {stack<char> st;for(int i 0; i < s.size(); i){char target s[i];if(!st.empty() && target st.top())st.pop();elsest.push(s[i]);}string ret…...

UE5 音效系统

一.音效管理 音乐一般都是WAV,创建一个背景音乐类SoudClass,一个音效类SoundClass。所有的音乐都分为这两个类。再创建一个总音乐类&#xff0c;将上述两个作为它的子类。 接着我们创建一个音乐混合类SoundMix&#xff0c;将上述三个类翻入其中&#xff0c;通过它管理每个音乐…...

2025.6.9总结(利与弊)

凡事都有两面性。在大厂上班也不例外。今天找开发定位问题&#xff0c;从一个接口人不断溯源到另一个 接口人。有时候&#xff0c;不知道是谁的责任填。将工作内容分的很细&#xff0c;每个人负责其中的一小块。我清楚的意识到&#xff0c;自己就是个可以随时替换的螺丝钉&…...

李沐--动手学深度学习--GRU

1.GRU从零开始实现 #9.1.2GRU从零开始实现 import torch from torch import nn from d2l import torch as d2l#首先读取 8.5节中使用的时间机器数据集 batch_size,num_steps 32,35 train_iter,vocab d2l.load_data_time_machine(batch_size,num_steps) #初始化模型参数 def …...