Qt自定义带前后缀图标的PushButton

写在前面

Qt提供QPushButton不满足带前后缀图标的需求,因此考虑自定义实现带前后缀图标的PushButton,方便后续快速使用。

效果如下:
1

2

3

4
同时可设置前后缀图标和文本之间间隙:
5

代码实现

通过前文介绍的Qt样式表底层实现

可以得知通过setStyleSheet()设置的样式,最终都会到paintEvent中绘制实现。

因此本示例的原理就是:前后缀图标和文本的绘制通过重写paintEvent实现,其他样式设置调用默认的paintEvent()处理。

完整代码如下:

#ifndef MPUSHBUTTON_H
#define MPUSHBUTTON_H
#include <QPushButton>
#include <QIcon>class MPushButton : public QPushButton
{Q_OBJECT
public:explicit MPushButton(QWidget* parent = nullptr);void setPrefixIcons(const QIcon(&icons)[4]);void setSuffixIcons(const QIcon(&icons)[4]);void setPrefixIconSize(const QSize& size);void setSuffixIconSize(const QSize& size);void setPrefixIconTextSpacing(int spacing);void setSuffixIconTextSpacing(int spacing);void hidePrefixIcon(bool bHide);void hideSuffixIcon(bool bHide);void setTextColor(const QColor(&colors)[4]);signals:protected:void paintEvent(QPaintEvent* event) override;private:QIcon m_prefixIcons[4];QIcon m_suffixIcons[4];QSize m_prefixIconSize;QSize m_suffixIconSize;int m_prefixIconTextSpacing;int m_suffixIconTextSpacing;bool m_hide_prefix_icon;bool m_hide_suffix_icon;QColor m_textColor[4];
};#endif // MPUSHBUTTON_H
#include "mpushbutton.h"#include <QPainter>
#include <QStyleOptionButton>
#include <QStylePainter>MPushButton::MPushButton(QWidget* parent): QPushButton{ parent }
{setAttribute(Qt::WA_Hover);m_prefixIconSize = QSize(20, 20);m_suffixIconSize = QSize(20, 20);m_prefixIconTextSpacing = 2;m_suffixIconTextSpacing = 2;m_hide_prefix_icon = true;m_hide_suffix_icon = true;
}void MPushButton::setPrefixIcons(const QIcon(&icons)[4])
{std::copy(std::begin(icons), std::end(icons), std::begin(m_prefixIcons));update();
}void MPushButton::setSuffixIcons(const QIcon(&icons)[4])
{std::copy(std::begin(icons), std::end(icons), std::begin(m_suffixIcons));update();
}void MPushButton::setPrefixIconSize(const QSize& size)
{m_prefixIconSize = size;update();
}void MPushButton::setSuffixIconSize(const QSize& size)
{m_suffixIconSize = size;update();
}void MPushButton::setPrefixIconTextSpacing(int spacing)
{m_prefixIconTextSpacing = spacing;update();
}void MPushButton::setSuffixIconTextSpacing(int spacing)
{m_suffixIconTextSpacing = spacing;update();
}void MPushButton::hidePrefixIcon(bool bHide)
{m_hide_prefix_icon = bHide;update();
}void MPushButton::hideSuffixIcon(bool bHide)
{m_hide_suffix_icon = bHide;update();
}void MPushButton::setTextColor(const QColor(&colors)[4])
{std::copy(std::begin(colors), std::end(colors), std::begin(m_textColor));update();
}void MPushButton::paintEvent(QPaintEvent* event)
{//通过父类QPushButton绘制样式表//注意:通过text-align设置文本对齐会影响图标设置效果QString qsText = text();setText("");	//设置文本为空,即不绘制文本,以便后面自己绘制QPushButton::paintEvent(event);	// 保留样式表的样式setText(qsText);QStylePainter painter(this);QStyleOptionButton option;initStyleOption(&option);//option.initFrom(this);QFontMetrics fm = painter.fontMetrics();QRect contentRect = style()->subElementRect(QStyle::SE_PushButtonContents, &option, this);int idx;if (!isEnabled()){idx = 3;}else if (isDown() || isChecked()){idx = 2;}else if (underMouse()){idx = 1;}else{idx = 0;}QPixmap prefixPixmap = m_prefixIcons[idx].pixmap(m_prefixIconSize);QPixmap suffixPixmap = m_suffixIcons[idx].pixmap(m_suffixIconSize);//自定义图标高度和文本间距。注意:前缀图标、文本、后缀图标要当成一个整体处理,否则无法应用样式表属性(如padding)int totalWidth = 0;int prefixStartX = 0;int contentStartX = 0;int suffixStartX = 0;if (m_hide_prefix_icon && m_hide_suffix_icon){//不显示前后缀图标totalWidth = fm.width(option.text);contentStartX = contentRect.left() + (contentRect.width() - totalWidth) / 2;}else if (!m_hide_prefix_icon && !m_hide_suffix_icon){//显示前后缀图标totalWidth = m_prefixIconSize.width() + fm.width(option.text) + m_suffixIconSize.width() + m_prefixIconTextSpacing + m_suffixIconTextSpacing;prefixStartX = contentRect.left() + (contentRect.width() - totalWidth) / 2;contentStartX = prefixStartX + m_prefixIconSize.width() + m_prefixIconTextSpacing;suffixStartX = prefixStartX + m_prefixIconSize.width() + m_prefixIconTextSpacing + fm.width(option.text) + m_suffixIconTextSpacing;}else if (m_hide_prefix_icon && !m_hide_suffix_icon){//只显示后缀图标totalWidth = fm.width(option.text) + m_suffixIconSize.width() + m_suffixIconTextSpacing;contentStartX = contentRect.left() + (contentRect.width() - totalWidth) / 2;suffixStartX = contentStartX + fm.width(option.text) + m_suffixIconTextSpacing;}else{//只显示前缀图标totalWidth = m_prefixIconSize.width() + fm.width(option.text) + m_prefixIconTextSpacing;prefixStartX = contentRect.left() + (contentRect.width() - totalWidth) / 2;contentStartX = prefixStartX + m_prefixIconSize.width() + m_prefixIconTextSpacing;}int startY = contentRect.top() + (contentRect.height() - fm.height()) / 2;int startPreY = contentRect.top() + (contentRect.height() - m_prefixIconSize.height()) / 2;int startSufY = contentRect.top() + (contentRect.height() - m_suffixIconSize.height()) / 2;if (!m_hide_prefix_icon){//前面已有当前状态判断,后续可扩展维护hover、presse状态的前缀图标painter.drawPixmap(prefixStartX, startPreY, m_prefixIconSize.width(), m_prefixIconSize.height(), prefixPixmap);}//方式一、通过drawText绘制文本// 优点:可自己指定绘制位置,// 缺点:无法应用样式表中字体相关的设置// 处理:自己维护正常、悬浮、点击、禁用时的文本颜色,自己绘制QColor textColor = m_textColor[idx];painter.setPen(textColor);painter.drawText(contentStartX, startY, fm.width(option.text), fm.height(), Qt::AlignCenter, option.text);//方式二、通过drawControl绘制文本//可通过QStylePainter绘制保留样式的文本//优点:可以应用样式表中字体相关的设置//缺点:无法指定绘制位置,遇到text-align或者padding样式属性值时会绘制两次文本,导致文本错位,同时与前后缀图标错位//style()->drawControl(QStyle::CE_PushButtonLabel, &option, &painter, this);if (!m_hide_suffix_icon){//前面已有当前状态判断,后续可扩展维护hover、presse状态的前缀图标painter.drawPixmap(suffixStartX, startSufY, m_suffixIconSize.width(), m_suffixIconSize.height(), suffixPixmap);}
}

使用示例:

#include "mpushbutton.h"
void MyWidget::mpushbutton_test()
{MPushButton* btn = new MPushButton(this);QIcon prefixIcons[4] = {QIcon(":/Image/avatar_normal.svg"), QIcon(":/Image/avatar_hover_pressed.svg"), QIcon(":/Image/avatar_hover_pressed.svg"), QIcon(":/Image/avatar_normal.svg")};btn->setPrefixIcons(prefixIcons);btn->setPrefixIconSize(QSize(16, 16));QIcon suffixIcons[4] = {QIcon(":/Image/avatar_normal.svg"), QIcon(":/Image/avatar_hover_pressed.svg"), QIcon(":/Image/avatar_hover_pressed.svg"), QIcon(":/Image/avatar_normal.svg")};btn->setSuffixIcons(suffixIcons);btn->setSuffixIconSize(QSize(16, 16));//可通过样式表设置背景、边框等样式QString qsBtnCSS = "QPushButton{font-family: Microsoft YaHei; font-size: 14px; font-weight: normal; color: #333333; border: 1px solid #DBDBDB;border-radius: 4px;text-align: left; padding-left: 20px;background: #FAFBFC; }""QPushButton:hover{ background: #EBEBEB;  }""QPushButton:pressed{background: #EBEBEB;  }""QPushButton:disabled{background: #EBEBEB;  }";btn->setStyleSheet(qsBtnCSS);//btn->setPrefixIconTextSpacing(10);		//可设置前后缀图标和文本之间的间隙//btn->setSuffixIconTextSpacing(4);QColor textColor[4] = {QColor("#333333"), QColor("#2982FF"), QColor("#0053D9"), QColor("#BDBDBD")};btn->setTextColor(textColor);btn->hidePrefixIcon(false);btn->hideSuffixIcon(false);btn->resize(96, 30);btn->setText("Admin");btn->move(100, 100);//btn->setEnabled(false);	//验证禁用效果
}

总结

通过自定义QPushButton,重写paintEvent,同时保留setStyleSheet()设置的样式,来实现带前后缀图标的MPushButton,以满足特殊场景使用。

这样实现的问题上面也有提到,自己绘制文本,需要考虑文本相关的样式(如text-align、padding)的影响。

后续也可按需扩展维护hover、pressed、disabled状态的前后缀图标。

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

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

相关文章

HiveSQL中last_value和first_value函数的应用

概述 今天做一个数据分析&#xff0c;其中有一列数据有些有数据有些没数据&#xff0c;因此我们需要把每数据的进行补充进来因此我们需要使用last_value 函数和over 结合使用&#xff0c;但是遇到一个比较奇葩的问题不能按照预期进行处理。 新说原因&#xff1a; 由于我们要处…

vue3-环境变量-JavaScript-axio-基础使用-lzstring-字符串压缩-python

文章目录 1.Vue3环境变量1.1.简介1.2.全局变量的引用1.3.package.json文件 2.axio2.1.promise2.2.安装2.3.配置2.3.1.全局 axios 默认值2.3.2.响应信息格式 2.4.Axios的拦截器2.4.1.请求拦截器2.4.2.响应拦截器2.4.3.移除拦截器2.4.4.自定义实例添加拦截器 3.lz-string3.1.java…

java项目数据库 mysql 迁移到 达梦

目录 一、下载安装达梦数据库 1、下载 2、解压 3、安装 二、迁移 三、更改SpringBoot 的 yml文件 1、达梦创建用户 2、修改yml 一、下载安装达梦数据库 1、下载 下载地址 https://eco.dameng.com/download/ 点击下载 开发版 (X86平台) , 然后选择操作系统并点击立…

“科技创新‘圳’在变革”2025深圳电子展

电子产业作为现代社会的核心驱动力之一&#xff0c;正以前所未有的速度发展。在这样的背景下&#xff0c;深圳作为中国的经济特区和创新高地&#xff0c;又一次迎来了备受瞩目的盛会——2025深圳电子展览会。本次展览会定于2025年4月9日至11日&#xff0c;在深圳会展中心&#…

剪画小程序:手机提取人声和伴奏

在音乐的海洋中&#xff0c;我们常常渴望更纯粹地感受歌手的嗓音魅力。 如今&#xff0c;有了 剪画&#xff0c;人声分离不再是难题&#xff01; 想象一下&#xff0c;当您沉浸在一首动人的歌曲中&#xff0c;却希望更清晰地捕捉到歌手声音中的每一个微妙情感。 无论是经典老…

算能端侧 AI 盒子 Stable Diffusion 一秒一张图:AirBox BM1684X

本篇文章聊聊基于 端侧 AI 计算设备&#xff0c;20~30 瓦功耗运行大模型的算能 AirBox。 写在前面 去年的双十二的时候&#xff0c;在群里看到了一张照片&#xff0c;“手掌大小的 NUC”&#xff0c;但是能够跑大模型。 这个草就种下了。 今年 7 月初的时候&#xff0c;在上…

学习008-02-04-09 Assign a Standard Image(分配标准图像)

Assign a Standard Image&#xff08;分配标准图像&#xff09; This lesson explains how to associate an entity class with a standard image from the DevExpress.Images assembly. This image illustrates the entity class in the following sections of the UI: 本课介…

C# 知识点总结

入门 C#程序在.NET上运行&#xff0c;.NET framework包含两个部分&#xff1a; ①&#xff1a;.NET framework类库 ②&#xff1a;公共语言运行库CLR&#xff08;.NET虚拟机&#xff09; CLS&#xff08;公共语言规范&#xff09; CTS&#xff08;通用类型系统&#xff09; .N…

ubuntu20.04安装nginx,mysql8,php7.4详细教程,包成功

目录 1.更新索引 2.安装 Nginx 1.安装 Nginx&#xff1a; 2.启动 Nginx 服务并设置为开机自启&#xff1a; 3.开放防火墙的 80 端口&#xff1a; 4.检查 Nginx 是否正常运行&#xff1a; 3.安装 MySQL 8.0 1.首先&#xff0c;安装 MySQL 的仓库&#xff1a; 安装过程中你会看…

RewardBench:Evaluating Reward Models for Language Modeling

Leaderboard&#xff1a; https://hf.co/spaces/allenai/reward-bench Code&#xff1a; https://github.com/allenai/reward-bench Dataset&#xff1a; https://hf.co/datasets/allenai/reward-bench 在人类偏好的强化学习&#xff08;RLHF&#xff09;过程中&#xff0c;奖励…

【Vulnhub系列】Vulnhub_Seattle_003靶场渗透(原创)

【Vulnhub系列靶场】Vulnhub_Seattle_003靶场渗透 原文转载已经过授权 原文链接&#xff1a;Lusen的小窝 - 学无止尽&#xff0c;不进则退 (lusensec.github.io) 一、环境准备 1、从百度网盘下载对应靶机的.ova镜像 2、在VM中选择【打开】该.ova 3、选择存储路径&#xff0…

【AI大模型】-- 应用部署

一、GPU价格参考 有些在京东就能买到&#xff1a;https://item.jd.com/10065826100148.html美国商务部限制 GPU 对华出口的算力不超过 4800 TOPS 和带宽不超过 600 GB/s&#xff0c;导致最强的 H100 和 A100 禁售。英伟达随后推出针对中国市场的 A800 和 H800。 H100 与 A100&…

CATIA V5R21安装包下载及图文安装教程

大家好&#xff0c;今天给大家分享下catia安装教程 注意安装前请退出杀毒软件&#xff0c;防止误报影响安装进程 下载链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;ypc6 01 在电脑D盘新建文件夹命名为CATIA,将下载的软件压缩包放置在该文件夹。 鼠标右击【C…

淘宝测试环境治理实践

去年之前&#xff0c;阿里巴巴的淘天集团测试环境是以领域方式运作&#xff1a;不局限测试环境治理本身&#xff0c;从测试模式方法论及用好测试环境思路引领集团测试环境治理。领域运作最难的是“统一思想”。业务进一步细分调整后&#xff0c;测试环境治理策略理应由业务方自…

【MetaGPT系列】【MetaGPT完全实践宝典——多智能体实践】

目录 前言一、智能体1-1、Agent概述1-2、Agent与ChatGPT的区别 二、多智能体框架MetaGPT2-1、安装&配置2-2、使用已有的Agent&#xff08;ProductManager&#xff09;2-3、多智能体系统介绍2-4、多智能体案例分析2-4-1、构建智能体团队2-4-2、动作/行为 定义2-4-3、角色/智…

若能重回白宫,特朗普称将把比特币列为美国战略储备资产!

KlipC报道&#xff1a;当地时间7月29日&#xff0c;美国前总统特朗普参加比特币2024大会&#xff0c;并在会上宣布称&#xff0c;如果重返白宫&#xff0c;他将把比特币列为美国战略储备资产。讲话期间&#xff0c;比特币价格一度上涨到6.9万美元大关。 特朗普表示&#xff1a…

Photos框架 - 自定义媒体选择器(UI预览)

引言 在前面的博客中我们已经介绍了使用媒体资源数据的获取&#xff0c;以及自定义的媒体资源选择列表页。在一个功能完整的媒体选择器中&#xff0c;预览自然是必不可少的&#xff0c;本篇博客我们就来实现一个资源的预览功能&#xff0c;并且实现列表和预览的数据联动效果。…

前端基于 axios 实现批量任务调度管理器 demo

一、背景介绍 这是一个基于 axios 实现的批量任务调度管理器的 demo。它使用了axios、promise 等多种技术和原理来实现批量处理多个异步请求&#xff0c;并确保所有请求都能正确处理并报告其状态。 假设有一个场景&#xff1a;有一个任务列表&#xff0c;有单个任务的处理功能…

PyQt ERROR:ModuleNotFoundError: No module named ‘matplotlib‘

Solution:打开cmd输入指令下载malplotlib pip install matplotlib

2024-07-27 Unity Excel —— 使用 EPPlus 插件读取 Excel 文件

文章目录 1 前言2 项目地址3 使用方法3.1 写入 Excel3.2 读取 Excel3.3 读写 csv 文件 4 ExcelSheet 代码 1 前言 ​ 前几日&#xff0c;一直被如何在 Unity 中读取 Excel 的问题给困扰&#xff0c;网上搜索相关教程相对古老&#xff08;4、5 年以前了&#xff09;。之前想用 …