V VeiSoft 小威软件园

小威软件园

共 6 个软件

VLibrary 组件库文档

手册 · VButton 自定义按钮组件

VButton 自定义按钮组件

概述

VButton 是一个基于 Qt 的自定义按钮组件,使用纯 painter 绘制,不依赖 QSS 样式表,避免样式污染问题。

功能特性

  • 纯 painter 绘制,无 QSS 依赖
  • 8 种内置样式变体(Variant),覆盖常见按钮需求
  • 自定义颜色支持(ColorOutlined / ColorGhost 模式)
  • 平滑的 hover / press 动画过渡
  • 涟漪(Ripple)点击动效,Material Design 风格,支持动态配置
  • 支持图标 + 文本组合显示
  • 支持长按功能
  • 圆角背景设计
  • 焦点环显示(1s 自动渐隐动画)
  • 支持 VMenu 弹出菜单,菜单关闭时自动重置按压状态
  • D-Pointer (Pimpl) 架构,头文件精简

样式变体(Variant)

变体说明背景边框文字
Default默认白色按钮白色/灰色(hover)浅灰主题色
Primary主题色实心按钮主题色主题色白色
Outlined轮廓按钮透明主题色主题色
Filled主题色淡背景按钮主题色低alpha透明主题色
Ghost幽灵按钮透明透明主题色
Dashed虚线边框按钮透明主题色(虚线)主题色
ColorOutlined彩色轮廓按钮(可自定义颜色)自定义色低alpha自定义色自定义色
ColorGhost彩色幽灵按钮(可自定义颜色)透明透明主题色

ColorGhost 变体

ColorGhost 是 Ghost 模式的增强版,文字跟随主题色(亮色→黑色,暗色→白色),hover/pressed 时的背景浮色可通过 setColor() 自定义:

状态背景边框文字
Normal透明透明主题色
Hover自定义色 alpha=10透明主题色
Pressed自定义色 alpha=25透明主题色
VButton *btn = new VButton("RedGhost", this);
btn->setVariant(VButton::ColorGhost);
btn->setColor(QColor(235, 0, 11));  // hover/pressed 浮色为红色

快速开始

基本使用

#include "VButton.h"

// 创建按钮(仅图标)
VButton *button = new VButton(parent);
button->setIcon(QIcon(":/icons/error.svg"));
button->setIconSize(QSize(16, 16));
button->setFixedSize(32, 32);

// 连接信号
connect(button, &VButton::clicked, this, &MyClass::onButtonClicked);

创建带文本的按钮

VButton *button = new VButton("Primary", parent);
button->setVariant(VButton::Primary);       // 设置样式变体
button->setFixedSize(120, 36);

使用颜色自定义

// ColorOutlined 模式——文字和边框使用自定义色
VButton *warningBtn = new VButton("Warning", this);
warningBtn->setVariant(VButton::ColorOutlined);
warningBtn->setColor(QColor(255, 149, 0));

// ColorGhost 模式——文字为主题色,hover 浮色自定义
VButton *ghostBtn = new VButton("RedGhost", this);
ghostBtn->setVariant(VButton::ColorGhost);
ghostBtn->setColor(QColor(235, 0, 11));

使用长按功能

VButton *button = new VButton("+", this);
button->setFixedSize(24, 24);

// 连接长按信号(count 为当前长按触发次数)
connect(button, &VButton::longPressed, this, [=](int count) {
    // 长按处理逻辑,count 从 1 开始递增
});

// 连接长按结束信号(totalPressCount 为长按期间总触发次数)
connect(button, &VButton::longPressReleased, this, [=](int totalPressCount) {
    // 长按结束处理逻辑
});

// 默认情况下长按每次触发也会发送 clicked() 信号,可通过以下方式关闭
button->setEmitPressedDuringLongPress(false);

API 参考

构造函数

explicit VButton(QWidget *parent = nullptr);
explicit VButton(const QString &text, QWidget *parent = nullptr);

样式变体

enum Variant {
    Default,     // 默认白色按钮
    Primary,     // 主题色实心按钮
    Outlined,    // 轮廓按钮
    Filled,      // 主题色淡背景按钮
    Ghost,       // 幽灵按钮(透明,hover 显示浅灰背景)
    Dashed,      // 虚线边框按钮
    ColorOutlined, // 彩色轮廓按钮(自定义颜色,有背景和边框)
    ColorGhost   // 彩色幽灵按钮(透明,hover 浮色可自定义,文字为主题色)
};

Variant variant() const;
void setVariant(Variant variant);

自定义颜色

QColor color() const;
void setColor(const QColor &color);

信号

信号描述
clicked(bool checked = false)继承自 QPushButton,按钮点击时触发
longPressed(int count)按钮长按时触发,初始延迟 500ms,之后每 100ms 重复触发,count 为当前触发次数(从1开始)
longPressReleased(int totalPressCount)长按结束(按钮释放)时触发,totalPressCount 为长按期间总触发次数

长按启用

bool isLongPressEnabled() const;
void setLongPressEnabled(bool enable);
方法描述
isLongPressEnabled()获取长按功能是否启用
setLongPressEnabled(bool)设置长按功能是否启用,默认为 false(需手动开启)

长按控制

bool isEmitPressedDuringLongPress() const;
void setEmitPressedDuringLongPress(bool enable);
方法描述
isEmitPressedDuringLongPress()获取长按时是否同时发射 clicked() 信号
setEmitPressedDuringLongPress(bool)设置长按时是否同时发射 clicked() 信号,默认为 true

长按延迟配置

int longPressInitialDelay() const;
void setLongPressInitialDelay(int ms);

int longPressRepeatDelay() const;
void setLongPressRepeatDelay(int ms);
方法描述
longPressInitialDelay() / setLongPressInitialDelay()获取/设置长按首次触发延迟(ms),默认 500
longPressRepeatDelay() / setLongPressRepeatDelay()获取/设置长按重复触发间隔(ms),默认 100

长按参数

参数默认值说明
_initialDelay500ms首次触发延迟(可通过 setLongPressInitialDelay 修改)
_repeatDelay100ms重复触发间隔(可通过 setLongPressRepeatDelay 修改)

涟漪效果

涟漪点击动效,点击时以鼠标位置为中心扩散半透明圆波,提供清晰的视觉反馈。

bool isRippleEnabled() const;
void setRippleEnabled(bool enable);

QColor rippleColor() const;
void setRippleColor(const QColor &color);
方法描述
isRippleEnabled() / setRippleEnabled()获取/设置涟漪是否启用,默认 true
rippleColor() / setRippleColor()获取/设置涟漪颜色;传入空 QColor 时自动推导(Primary→白色,其他→主题色)

涟漪颜色自动推导:

  • Primary 变体(深色背景)→ 白色涟漪,与背景形成对比
  • 其他变体(浅色背景)→ VTheme::color().primary 主题色涟漪
  • 可通过 setRippleColor() 自定义覆盖

VMenu 弹出菜单

VButton 支持绑定自定义 VMenu 弹出菜单,菜单关闭时自动重置按钮按压状态,防止因菜单交互导致 pressProgress 卡住。

VMenu* menu() const;
void setMenu(VMenu* menu);
方法描述
menu()获取当前绑定的 VMenu
setMenu(VMenu*)设置弹出菜单,内部自动关联 QPushButton::setMenu,并在菜单 aboutToHide 时重置 pressProgress 动画
VButton *btn = new VButton("菜单", this);
VMenu *popupMenu = new VMenu(this);
popupMenu->addAction("选项1");
popupMenu->addAction("选项2");
btn->setMenu(popupMenu);

动画属性(Q_PROPERTY)

属性类型说明
hoverProgressqrealhover 动画进度 0.0–1.0,过渡时间 500ms
pressProgressqrealpress 动画进度 0.0–1.0,过渡时间 80ms
focusRingProgressqreal焦点环动画进度 0.0–1.0,过渡时间 300ms

设计特点

纯 painter 绘制

  • 不使用 QSS 样式表
  • 避免样式污染
  • 更好的性能和可控性

动画效果

  • hover 进出使用 500ms QPropertyAnimation 平滑过渡
  • press 按下/释放使用 80ms 快速过渡(颜色渐变)
  • 焦点环显示/消失使用 300ms 过渡
  • 颜色通过线性插值实现渐变效果
  • Primary 模式支持按压缩小阴影效果

涟漪动效(Ripple)

  • 点击时以鼠标位置为圆心,扩散半透明圆波
  • 半径扩张使用 easeOutCubic 缓动函数
  • 透明度从 0.2 线性衰减至 0
  • 单次涟漪持续 600ms
  • 60fps 定时器驱动,多涟漪可共存叠加
  • 自动裁剪到按钮圆角边界,不超出按钮区域
  • 空闲时定时器自动停止,零 CPU 开销

圆角设计

  • 默认圆角半径 6px,动态适配按钮高度(不超过高度/4)
  • 边框宽度 1px,焦点环宽度 2px

焦点环

  • 按钮获得焦点时内部绘制半透明焦点环
  • 焦点环颜色为主题色 alpha=40%
  • 获得焦点 1 秒后自动缓慢渐隐消失
  • Filled、Ghost、ColorGhost、ColorOutlined 风格下不显示焦点环

长按功能

  • 按钮按下 500ms 后触发第一次长按信号
  • 之后每 100ms 重复触发长按信号
  • 释放按钮时停止触发

使用示例

示例 1:各种样式变体

VButton *defaultBtn = new VButton("Default", this);
defaultBtn->setVariant(VButton::Default);
defaultBtn->setFixedSize(120, 36);

VButton *primaryBtn = new VButton("Primary", this);
primaryBtn->setVariant(VButton::Primary);
primaryBtn->setFixedSize(120, 36);

VButton *outlinedBtn = new VButton("Outlined", this);
outlinedBtn->setVariant(VButton::Outlined);
outlinedBtn->setFixedSize(120, 36);

VButton *filledBtn = new VButton("Filled", this);
filledBtn->setVariant(VButton::Filled);
filledBtn->setFixedSize(120, 36);

VButton *ghostBtn = new VButton("Ghost", this);
ghostBtn->setVariant(VButton::Ghost);
ghostBtn->setFixedSize(120, 36);

VButton *dashedBtn = new VButton("Dashed", this);
dashedBtn->setVariant(VButton::Dashed);
dashedBtn->setFixedSize(120, 36);

示例 2:ColorGhost 彩色幽灵按钮

VButton *redGhost = new VButton("RedGhost", this);
redGhost->setVariant(VButton::ColorGhost);
redGhost->setColor(QColor(235, 0, 11));
redGhost->setFixedSize(120, 36);

VButton *greenGhost = new VButton("GreenGhost", this);
greenGhost->setVariant(VButton::ColorGhost);
greenGhost->setColor(QColor(52, 199, 89));
greenGhost->setFixedSize(120, 36);

VButton *blueGhost = new VButton("BlueGhost", this);
blueGhost->setVariant(VButton::ColorGhost);
blueGhost->setColor(QColor(22, 119, 255));
blueGhost->setFixedSize(120, 36);

示例 3:图标 + 文字按钮

VButton *btn = new VButton("设置", this);
btn->setIcon(QIcon(":/icons/setting.png"));
btn->setIconSize(QSize(16, 16));
btn->setVariant(VButton::Ghost);
btn->setFixedSize(100, 36);

示例 4:长按按钮

VButton *plusBtn = new VButton("+", this);
plusBtn->setVariant(VButton::Filled);
plusBtn->setFixedSize(48, 48);

connect(plusBtn, &VButton::clicked, [=]() {
    // 普通点击处理
});

connect(plusBtn, &VButton::longPressed, [=](int count) {
    // 长按处理(连续触发),count 为当前触发次数
});

示例 5:涟漪效果

VButton *rippleBtn = new VButton("Click Me", this);
rippleBtn->setVariant(VButton::Primary);
rippleBtn->setFixedSize(140, 40);

// 关闭涟漪
rippleBtn->setRippleEnabled(false);

// 自定义涟漪颜色
VButton *customRipple = new VButton("Custom", this);
customRipple->setVariant(VButton::Outlined);
customRipple->setRippleColor(QColor(255, 100, 50));
customRipple->setFixedSize(140, 40);

注意事项

  1. VButton 使用纯 painter 绘制,不依赖 QSS 样式表
  2. 建议设置固定大小(setFixedSize)
  3. 支持文本和图标同时显示
  4. 继承自 QPushButton,可使用所有 QPushButton 的功能
  5. 长按信号在按钮按下后首次触发,之后按重复间隔触发,count 从 1 开始递增;延迟可通过 setLongPressInitialDelay() / setLongPressRepeatDelay() 配置(默认 500ms / 100ms)
  6. 长按结束时发射 longPressReleased(int totalPressCount),传递总触发次数
  7. 默认长按每次触发也会发射 clicked() 信号,可通过 setEmitPressedDuringLongPress(false) 关闭
  8. setColor() 仅在 ColorOutlined 和 ColorGhost 模式下生效
  9. ColorGhost 模式下文字颜色自动跟随主题,不受 setColor 影响
  10. 涟漪默认开启,传入空 QColor 时颜色自动推导(Primary→白色,其他→主题色)
  11. 涟漪与 press 动画互不冲突:涟漪提供点击位置反馈,press 动画驱动颜色过渡
  12. 代码采用 D-Pointer (Pimpl) 架构,实现细节隐藏在 VButtonPrivate / VButtonStyle 中
  13. setMenu(VMenu*) 内部自动关联 QPushButton::setMenu,并在菜单关闭时强制重置 pressProgress 为 0,防止 press 动画卡住

版本历史

v2.0

  • 按钮基础高度改为在构造时读取跨组件令牌 VTheme::control().widgetHeight(默认 33)作为初始参考值
  • 移除对主题变化的订阅(onThemeChanged):widgetHeight 仅作为初始化参考,运行时不随主题动态改高度,需固定尺寸请用 setFixedSize()/setFixedHeight() 显式指定,避免破坏外部布局

v1.9

  • 新增 menu() / setMenu(VMenu*) 接口,支持绑定自定义 VMenu 弹出菜单
  • setMenu() 内部关联 QPushButton::setMenu,并在菜单 aboutToHide 时强制重置 pressProgress,防止因菜单交互导致 press 动画卡住

v1.8

  • 新增涟漪(Ripple)点击动效:点击位置扩散半透明圆波,easeOutCubic 缓动,600ms 持续
  • 涟漪颜色自动推导:Primary 变体用白色,其他用主题色
  • 新增 setRippleEnabled() / isRippleEnabled() / setRippleColor() / rippleColor() API
  • 移除 press 缩放挤压效果和内容偏移(涟漪替代)

v1.7

  • 代码分层拆分:VButtonPrivate.h/cpp(数据+生命周期)+ VButtonStyle.h/cpp(绘制逻辑)
  • D-Pointer (Pimpl) 重构:VButton 头文件精简至 79 行,所有实现细节隐藏
  • 修复动画竞争条件:6 处动画启动点先保存当前值再调用 setCurrentTime(0)
  • 优化点击反馈:press 动画 80ms + 1.5px 内容偏移 + 2% 缩放挤压
  • 长按 timer 改为延迟创建(仅在 _longPressEnabled=true 时)
  • fontMetrics 复用优化、常量替代魔数、删除未使用函数

v1.5

  • Warning 变体重命名为 ColorOutlined
  • 焦点环透明度从 60% 调整为 40%
  • 新增焦点环动画:获得焦点后显示 1 秒,然后缓慢消失
  • Filled、Ghost、ColorGhost、ColorOutlined 风格下不显示焦点环

v1.4

  • longPressed 信号改为 longPressed(int count),携带当前触发次数
  • 新增 longPressReleased(int totalPressCount) 信号,长按结束时触发
  • 新增 isLongPressEnabled() / setLongPressEnabled() 总开关,默认关闭,需手动开启长按功能
  • 新增 isEmitPressedDuringLongPress() / setEmitPressedDuringLongPress(bool) 开关,默认开启,控制长按时是否同时发送 clicked() 信号
  • 新增 longPressInitialDelay() / setLongPressInitialDelay() 和 longPressRepeatDelay() / setLongPressRepeatDelay() 接口,支持动态配置长按延迟
  • 修复 paintEvent 中遗漏的 drawShadow() 和 drawFocusRing() 调用
  • 移除未使用的头文件引用,Q_ENUMS 升级为 Q_ENUM

v1.3

  • 新增 ColorGhost 变体:透明背景 + 主题色文字 + 自定义 hover/pressed 浮色

v1.2

  • 新增 ColorOutlined 变体:支持自定义颜色的彩色轮廓按钮
  • 新增 setVariant() / variant() 和 setColor() / color() 接口
  • 新增所有样式变体(Default / Primary / Outlined / Filled / Ghost / Dashed)
  • 新增 hover / press 动画过渡效果
  • 新增焦点环绘制
  • 新增 Primary 模式阴影效果

v1.1

  • 新增文本显示支持
  • 新增长按功能
  • 新增 longPressed() 信号
  • 添加带文本参数的构造函数

v1.0

  • 初始版本
  • 纯 painter 绘制
  • hover 状态效果
  • 圆角背景设计
  • 图标支持