[流光按钮]

Qt、C++复刻:[流光按钮]

效果

flowingRayButton.h 流动光线按钮

#ifndef FLOWINGRAYBUTTON_H
#define FLOWINGRAYBUTTON_H

#include <QFrame>
#include <QPushButton>
#include <QWidget>
#include <QLineEdit>
#include <QGraphicsBlurEffect>
#include <QRect>
#include <QSize>
#include <Qt>
#include <QTimer>
#include <QParallelAnimationGroup>
#include <QPropertyAnimation>
#include <QEasingCurve>
#include <QPoint>
#include <QSequentialAnimationGroup>
#include <QAbstractAnimation>
#include <QRegularExpression>
#include <QBrush>
#include <QColor>
#include <QCursor>
#include <QFont>
#include <QPainter>
#include <QPainterPath>
#include <QLinearGradient>
#include <QDebug>
// 流动光线按钮

class FlowingRayButton : public QWidget
{
	Q_OBJECT
public:
	FlowingRayButton(QWidget *parent = nullptr);
	~FlowingRayButton();

	void enterEvent(QEvent *event) override;//重写处理鼠标光标进入部件的事件
	void leaveEvent(QEvent *event) override;//重写处理鼠标光标离开部件的事件
	void paintEvent(QPaintEvent *event) override;//重写绘制事件



	void setBorder(int border = 5); // 设置按钮在QFrame中的大小
	void setStyleSheetConfig();     // 根据样式重新配置(解析样式设置)
	QPushButton *getFlowingRayButton();

	void startTimer();

	void stopTimer();

	void useTimer();

private:
	QPushButton *m_pPushButton;
	int border_radius;              // 边框圆角
	int border;                     // 边界
	QTimer *m_pTimer;
	int rect_1_offset;              //
	int rect_2_offset;
	int rect_1_start;
	int rect_2_start;
	int init_x;
	int flag;
	void initUI();
	void initAnimationConfig();     // 初始化动画配置



private slots:
	void offsetUpdate();            // 偏移更新
};

#endif // FLOWINGRAYBUTTON_H

flowingRayButton.cpp 流动光线按钮

#include "flowingRayButton.h"
#include <QMouseEvent>
// 流动光线按钮
FlowingRayButton::FlowingRayButton(QWidget *parent)
	: QWidget(parent)
{
	border_radius = 0;
	border = 5;
	initUI();


}

FlowingRayButton::~FlowingRayButton()
{

}




void FlowingRayButton::initUI()
{
	this->resize(300, 100);
	this->setStyleSheet("QFrame{"
				  "	background-color: rgba(255, 255, 255,0);"
				  "	border:none;"
				  "	border-radius:10px;"
				  " Rborder-width:5px;"
				  "}"
				  "QPushButton{border-radius: 5px;color:#ff0066;}"
				  );
	m_pPushButton = new QPushButton(this);
	setBorder();

	QFont font;
	font.setPointSize(25);

	m_pPushButton->setFont(font);
	m_pPushButton->setText("Start Coding");
	connect(m_pPushButton,&QPushButton::clicked,[=] {
		if (m_pTimer->isActive()) {
			m_pTimer->stop();
		}
		else {
			m_pTimer->start();
		}

	});

	m_pTimer = new QTimer(this);
	m_pTimer->setInterval(10);      //间隔毫秒
	connect(m_pTimer, SIGNAL(timeout()), this, SLOT(offsetUpdate()));
	initAnimationConfig();
}

void FlowingRayButton::setBorder(int border)
{
	int btn_width = this->width() - border * 2;
	int btn_height = this->height() - border * 2;
	int btn_x = border;
	int btn_y = border;
	m_pPushButton->setGeometry(QRect(btn_x, btn_y, btn_width, btn_height));
}

 // 根据样式重新配置(解析样式设置)
void FlowingRayButton::setStyleSheetConfig()
{
	/*匹配规则;
	 * 注意:正则表达式在找到第一个匹配项后就会停止查找,所以它不会再次匹配。
	 * 从头开始查找匹配 border-radius: 的部分,然后尝试匹配一个或多个数字字符 (\\d+),而后匹配 px;
	 * 使用 \\s* 来匹配可能存在的空格字符,包括零个或多个空格;
	 * \\d+表示匹配一个或多个数字字符
	 * 使用 (?P<border_radius>\\d+) 来匹配 border-radius 后面的数字,并将其命名为 border_radius;*/
	QRegularExpression radius_match("border-radius:\\s*(?P<border_radius>\\d+)px;");
	QRegularExpressionMatch radius_result = radius_match.match(this->styleSheet());
	if (radius_result.hasMatch())
	{
		//提取捕获组中命名为 border_radius的内容
		border_radius = radius_result.captured("border_radius").toInt();
	}

	QRegularExpression Rborder_width_match("Rborder-width:\\s*(?P<Rborder_width>\\d+)px;");
	QRegularExpressionMatch Rborder_width_result = Rborder_width_match.match(this->styleSheet());
	if (Rborder_width_result.hasMatch()) {
		border = Rborder_width_result.captured("Rborder_width").toInt();
	}

	// 根据样式重新配置QPushButton边界
	setBorder(border);
	initAnimationConfig();
}

// 初始化动画配置
void FlowingRayButton::initAnimationConfig()
{
	rect_1_offset = 0;
	rect_2_offset = 0;
	rect_1_start = 0;
	rect_2_start = -this->width();
	init_x = -this->width();
	flag = 0;
}



// 偏移更新
void  FlowingRayButton::offsetUpdate()
{
	if(rect_1_offset >= this->width()&&flag==0) {
		rect_1_offset = 0;
		rect_1_start = init_x;
		flag=1;
	}
	if(rect_1_offset >= this->width()*2&&flag==1) {
		rect_1_offset = 0;
		rect_1_start = init_x;
	}

	if (rect_2_offset >= this->width() * 2) {
		rect_2_offset = 0;
		rect_2_start = init_x;
	}

	rect_1_offset += 3;
	rect_2_offset += 3;

	update();
}

//重写处理鼠标光标进入部件的事件
void FlowingRayButton::enterEvent(QEvent *event)
{
	// 调用父类的 enterEvent 函数,以保持默认行为
	QWidget::enterEvent(event);
}

//重写处理鼠标光标离开部件的事件
void FlowingRayButton::leaveEvent(QEvent *event)
{
	// 调用父类的 leaveEvent 函数,以保持默认行为
	QWidget::leaveEvent(event);
}

//重写绘制事件
void FlowingRayButton::paintEvent(QPaintEvent *event)
{
	// 调用父类的 paintEvent 函数,以保持默认行为
	QWidget::paintEvent(event);

	QPainterPath path;
	//添加一个带有圆角的矩形路径
	path.addRoundedRect(0, 0, this->width(), this->height(), border_radius, border_radius);

	QPainter painter(this);
	//设置渲染提示; QPainter::Antialiasing 是一种渲染提示,用于抗锯齿绘制,使得图形边缘更加平滑
	painter.setRenderHint(QPainter::Antialiasing);
	//设置画笔; Qt::NoPen 表示不使用画笔,也就是不绘制边框
	painter.setPen(Qt::NoPen);
	//设置剪裁路径,即限制绘制区域为指定的路径范围内
	painter.setClipPath(path);

	//线性渐变
	QLinearGradient gradient_1(rect_1_start + rect_1_offset, 0, rect_1_start + rect_1_offset + this->width(), 0);
	//在(0,1)之间设置颜色的渐变过程,将一个颜色逐渐过渡到另一个
	gradient_1.setColorAt(0, QColor(0, 164, 128, 230));
	gradient_1.setColorAt(0.166, QColor(13, 88, 166, 230));
	gradient_1.setColorAt(0.333, QColor(118, 8, 170, 230));
	gradient_1.setColorAt(0.5, QColor(255, 144, 0, 230));
	gradient_1.setColorAt(0.666, QColor(255, 255, 0, 230));
	gradient_1.setColorAt(0.833, QColor(165, 239, 0, 230));
	gradient_1.setColorAt(1, QColor(83, 223, 0, 230));

	painter.setBrush(gradient_1);
	painter.drawRect(rect_1_start + rect_1_offset, 0, this->width(), this->height());

	QLinearGradient gradient_2(rect_2_start + rect_2_offset, 0,rect_2_start + rect_2_offset + this->width(), 0);
	gradient_2.setColorAt(0, QColor(0, 164, 128, 230));
	gradient_2.setColorAt(0.166, QColor(13, 88, 166, 230));
	gradient_2.setColorAt(0.333, QColor(118, 8, 170, 230));
	gradient_2.setColorAt(0.5, QColor(255, 144, 0, 230));
	gradient_2.setColorAt(0.666, QColor(255, 255, 0, 230));
	gradient_2.setColorAt(0.833, QColor(165, 239, 0, 230));
	gradient_2.setColorAt(1, QColor(83, 223, 0, 230));

	painter.setBrush(gradient_2);
	painter.drawRect(rect_2_start + rect_2_offset, 0, this->width(), this->height());

}

QPushButton *FlowingRayButton::getFlowingRayButton()
{
	return m_pPushButton;
}

void FlowingRayButton::startTimer()
{
	m_pTimer->start();
}

void FlowingRayButton::stopTimer()
{
	m_pTimer->stop();
}

void FlowingRayButton::useTimer()
{
	if (m_pTimer->isActive()) {
		m_pTimer->stop();
	}
	else {
		m_pTimer->start();
	}
}



mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "flowingRayButton.h"
#include <QMouseEvent>
MainWindow::MainWindow(QWidget *parent)
	: QMainWindow(parent)
	, ui(new Ui::MainWindow)
{
	ui->setupUi(this);

	//隐藏最大化按钮|置顶
	setWindowFlags(Qt::FramelessWindowHint);
	this->setStyleSheet("background:#000000");

}

MainWindow::~MainWindow()
{
	delete ui;
}

提升FlowingRayButton

 hoveringRippleButton.h 悬浮波纹按钮

#ifndef HOVERINGRIPPLEBUTTON_H
#define HOVERINGRIPPLEBUTTON_H

#include <QFrame>
#include <QFrame>
#include <QPushButton>
#include <QWidget>
#include <QPainter>
#include <QPainterPath>
#include <QTimer>
#include <QMouseEvent>
#include <QPropertyAnimation>
#include <QtCore/qmath.h>

//悬浮波纹按钮
class HoveringRippleButton : public QFrame
{
    Q_OBJECT
public:
    HoveringRippleButton(QWidget *parent = nullptr);
    HoveringRippleButton(QWidget *parent = nullptr, const QRect &geometry = QRect(), const QSize &minSize = QSize());
    ~HoveringRippleButton();

private:
    QRect geometry;
    QSize minSize;
    QPushButton *m_pPushButton;
    int corner_radius;              // 按钮的圆角半径
    int radius_var;                 // 半径变化值
    int radius;                     // 起始半径
    qreal max_radius;               // 最大半径
    QPoint center;                  // 鼠标点击坐标
    QColor color;                   // 填充颜色
    int msec;                       // 定时时间
    QTimer *m_pTimer;
    void initUI();
    void initAnimationConfig();     // 初始化动画配置
    void enterEvent(QEvent *event) override;//重写处理鼠标光标进入部件的事件
    void leaveEvent(QEvent *event) override;//重写处理鼠标光标离开部件的事件
    void paintEvent(QPaintEvent *event) override;//重写绘制事件
private slots:
    void incRadius();
    void decRadius();

};

#endif // HOVERINGRIPPLEBUTTON_H

 hoveringRippleButton.cpp 悬浮波纹按钮

#include "hoveringRippleButton.h"
#pragma execution_character_set("utf-8")
//悬浮波纹按钮
HoveringRippleButton::HoveringRippleButton(QWidget *parent)
    : QFrame(parent)
{
    geometry=QRect(0,0,100,50);
    minSize =QSize(100,50);
    initUI();
}

HoveringRippleButton::HoveringRippleButton(QWidget *parent, const QRect &geometry, const QSize &minSize)
    : QFrame(parent), geometry(geometry), minSize(minSize)
{
    initUI();
}

HoveringRippleButton::~HoveringRippleButton()
{

}

void HoveringRippleButton::initUI()
{
    setMinimumSize(minSize);
    setStyleSheet("QFrame{"
                  "	background-color: rgb(46, 22, 177);"
                  "	border:none;"
                  "	border-radius:10px;"
                  "}"
                  "QPushButton{"
                  "	background-color: rgba(255, 255, 255, 0);"
                  "	color: rgb(255, 255, 255);"
                  "}");

    m_pPushButton = new QPushButton(this);
    m_pPushButton->setMinimumSize(minSize);
    m_pPushButton->setFixedSize(QSize(width(), height()));
    QFont font;
    font.setPointSize(25);
    m_pPushButton->setFont(font);
    m_pPushButton->setText("悬浮会变色喔");

    setGeometry(geometry);
    initAnimationConfig();
}

void HoveringRippleButton::initAnimationConfig()
{
    corner_radius = 10;                                     // 按钮的圆角半径
    radius_var = 2;                                         // 半径变化值
    radius = 0;                                             // 起始半径
    max_radius = qSqrt(width() * width() + height() * height());  // 最大半径
    center = QPoint();                                       // 鼠标点击坐标
    color = QColor(255, 89, 0);                              // 填充颜色
    msec = 10;                                               // 定时时间

    m_pTimer = new QTimer(this);
    m_pTimer->setInterval(msec);
    connect(m_pTimer,SIGNAL(timeout()), this, SLOT(incRadius()));
}

//重写处理鼠标光标进入部件的事件
void HoveringRippleButton::enterEvent(QEvent *event)
{
    // 调用父类的 enterEvent 函数,以保持默认行为
    QFrame::enterEvent(event);
    /* QCursor::pos() 获取当前鼠标的全局坐标
     * mapFromGlobal()将全局坐标转换为窗口内部相对坐标*/
    center = mapFromGlobal(QCursor::pos());
    m_pTimer->disconnect();
    connect(m_pTimer, SIGNAL(timeout()), this, SLOT(incRadius()));
    m_pTimer->start();
}

//重写处理鼠标光标离开部件的事件
void HoveringRippleButton::leaveEvent(QEvent *event)
{
    // 调用父类的 leaveEvent 函数,以保持默认行为
    QFrame::leaveEvent(event);
    center = mapFromGlobal(QCursor::pos());
    m_pTimer->disconnect();
    connect(m_pTimer, SIGNAL(timeout()), this, SLOT(decRadius()));
    m_pTimer->start();
}

//重写绘制事件
void HoveringRippleButton::paintEvent(QPaintEvent *event)
{
     // 调用父类的 paintEvent 函数,以保持默认行为
    QFrame::paintEvent(event);

    if (center.isNull()) {
        return;
    }

    QPainter painter(this);
    //设置渲染提示; QPainter::Antialiasing 是一种渲染提示,用于抗锯齿绘制,使得图形边缘更加平滑
    painter.setRenderHint(QPainter::Antialiasing);

    QBrush brush(color);
    painter.setBrush(brush);
    //设置画笔; Qt::NoPen 表示不使用画笔,也就是不绘制边框
    painter.setPen(Qt::NoPen);

    QPainterPath path;
    //添加一个带有圆角的矩形路径
    path.addRoundedRect(rect(), corner_radius, corner_radius);
    //设置剪裁路径,即限制绘制区域为指定的路径范围内
    painter.setClipPath(path);
    //绘制椭圆(长轴==长轴,就圆形)
    painter.drawEllipse(center, radius, radius);
}

void HoveringRippleButton::incRadius()
{
    radius += radius_var;
    if (radius > max_radius) {
        m_pTimer->stop();
        return;
    }
    update();
}

void HoveringRippleButton::decRadius()
{
    radius -= radius_var;
    if (radius < 0) {
        m_pTimer->stop();
        return;
    }

    update();
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值