QPushButton自绘按钮使用QPainter进行二维图形绘制,QPainter可以绘制各种图形,例如点、线、矩形、圆、椭圆等,QPainter也支持线性变换,例如平移、旋转缩放等,此外,QPainter也支持一些高级特性,例如反走样等等、像素混合、渐变填充等,在绘制前可以设置画笔、画刷、字体属性来控制绘制效果。
QPainter的使用需要一个“绘图设备”,绘图设备包括但不限于QWidget、QPixmap、QImage等。在定制窗口部件时只需要重新实现paintEvent()函数可以让我们随心所欲的控制窗口的外观、下面介绍使用QPainter绘制图片、形状、文字的方法。
按钮文字闪烁,按钮突出感强烈,点击、选中、悬浮等功能实现。
效果
主要涉及两个辅助类:
-
QFontMetrics
用于获取文本字体的像素高度与宽度 -
QBasicTimer
定时器,用于更新文本绘制。
原理:
-
利用QBasicTimer进行定时刷新。
-
文本绘制时,使用QColor来设置色调(H)、饱和度(S)、亮度(V),然后计算每一个字符的绘制坐标,进行单个绘制
BannerWidget.h
#ifndef PARA_BANNER_H
#define PARA_BANNER_H
#include <QWidget>
#include <QPushButton>
#include <QBasicTimer>
class BannerWidget : public QPushButton
{
Q_OBJECT
public:
explicit BannerWidget(QWidget *parent = 0);
~BannerWidget();
virtual void mousePressEvent(QMouseEvent *event) override;
virtual void mouseReleaseEvent(QMouseEvent *event) override;
public slots:
void setText(const QString &text);
protected:
// 绘制文本
void paintEvent(QPaintEvent *event);
// 定时刷新
void timerEvent(QTimerEvent *event);
void enterEvent(QEvent *);
void leaveEvent(QEvent *);
private:
QBasicTimer m_timer;
QString m_strText;
int m_nStep;
bool isHovered;
bool isClicked;
};
#endif
BannerWidget.cpp
#include <QPainter>
#include <QTimerEvent>
#include <QFont>
#include <QLinearGradient>
#include "bannerwidget.h"
#pragma execution_character_set("UTF-8")//解决汉字乱码
BannerWidget::BannerWidget(QWidget *parent)
: QPushButton(parent),
m_nStep(0),
m_strText(QString::fromLocal8Bit("一去丶二三里")),
isHovered(false),
isClicked(false)
{
setAutoFillBackground(true);
// 设置文字大小
QFont newFont = font();
newFont.setPointSize(newFont.pointSize() + 8);
setFont(newFont);
setCheckable(true);
m_timer.start(100, this);
}
BannerWidget::~BannerWidget()
{
m_timer.stop();
}
void BannerWidget::mousePressEvent(QMouseEvent *event)
{
isClicked = true;
isHovered = false;
if (isChecked()) {
setChecked(false);
}
else {
setChecked(true);
}
update();
QWidget::mouseReleaseEvent(event);
}
void BannerWidget::mouseReleaseEvent(QMouseEvent *event)
{
isClicked = false;
isHovered = true;
update();
QWidget::mouseReleaseEvent(event);
}
void BannerWidget::setText(const QString &text)
{
m_strText = text;
}
void BannerWidget::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
// 计算文本绘制的起始坐标
QFontMetrics metrics(font());
int x = (width() - metrics.width(m_strText)) / 2;
int y = (height() + metrics.ascent() - metrics.descent()) / 2;
QColor textColor;
QColor textColor2 = "#ECECB1";
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing,true);
// 上
QLinearGradient linearGradient(2, 1, this->width() - 2, 1);
linearGradient.setColorAt(0.2, "#848485");
linearGradient.setColorAt(1.0, "#FAFAFA");
painter.setPen(QPen(QBrush(linearGradient),2));
painter.drawLine(2, 1, this->width() - 2, 1);
// 左
QLinearGradient linearGradient2(0, 2, 0, this->height() - 3);
linearGradient2.setColorAt(0.2, "#848485");
linearGradient2.setColorAt(1.0, "#FAFAFA");
painter.setPen(QPen(QBrush(linearGradient2),4));
painter.drawLine(0, 2, 0, this->height() - 3);
// 右
QLinearGradient linearGradient3(this->width(), 2, this->width(), this->height() - 3);
linearGradient3.setColorAt(0.2, "#FAFAFA");
linearGradient3.setColorAt(1.0, "#848485");
painter.setPen(QPen(QBrush(linearGradient3),4));
painter.drawLine(this->width(), 2, this->width(), this->height() - 3);
// 下
QLinearGradient linearGradient4(2, this->height(),this->width() - 2, this->height());
linearGradient4.setColorAt(0.01, "#FAFAFA");
linearGradient4.setColorAt(0.02, "#000000");
linearGradient4.setColorAt(0.98, "#000000");
linearGradient4.setColorAt(1.0, "#848485");
painter.setPen(QPen(QBrush(linearGradient4),4));
painter.drawLine(2, this->height(), this->width() - 2, this->height());
if(isClicked){
QRect rect(2, 2, this->width() - 4, this->height() - 4);
painter.setPen(Qt::NoPen);
painter.setBrush(QColor("#000000"));
painter.drawRect(rect);
}
// 指定要绘制的图片(将图片路径替换为有效的图片路径)
if (isHovered) {
QRect rect(2, 2, this->width() - 4, this->height() - 4);
painter.drawPixmap(rect, QPixmap(":/img/backgroundPress.png"));
}
if(isChecked()){
for (int i = 0; i < m_strText.size(); ++i)
{
// 设置色调(H)、饱和度(S)、亮度(V)
int nIndex = (m_nStep + i) % 16;
textColor.setHsv((15 - nIndex) * 16, 255, 191);
painter.setPen(textColor);
// 单个字符绘制
painter.drawText(x, y, QString(m_strText[i]));
// 计算下一个字符的x坐标起始点
x += metrics.width(m_strText[i]);
}
}
else {
for (int i = 0; i < m_strText.size(); ++i)
{
painter.setPen(textColor2);
// 单个字符绘制
painter.drawText(x, y, QString(m_strText[i]));
// 计算下一个字符的x坐标起始点
x += metrics.width(m_strText[i]);
}
}
}
void BannerWidget::timerEvent(QTimerEvent *event)
{
Q_UNUSED(event);
if (event->timerId() == m_timer.timerId())
{
++m_nStep;
update();
}
else
{
QPushButton::timerEvent(event);
}
}
void BannerWidget::enterEvent(QEvent *)
{
isHovered = true;
update();
}
void BannerWidget::leaveEvent(QEvent *)
{
isHovered = false;
update();
}