在 Qt 的 2D 绘图系统中,QPainter 是当之无愧的绘图核心,而 QPen 和 QBrush 则分别掌控着轮廓线与填充区域的样式。然而,不少开发者可能会认为 QPen 仅能设置单一颜色(如 Qt::red) ,这无形中限制了用户界面的视觉表现力。
实际上,QPen 不仅能设置颜色,更可以绑定一个完整的 QBrush 对象! 这意味着,你可以使用线性渐变、径向渐变、纹理甚至自定义图案来绘制线条、边框和文字轮廓,彻底告别单调的单色线条。
本文将深入解析 QPen 与 QBrush 的组合机制,并通过多个实战案例(包括渐变进度条、霓虹文字、仪表盘边框等),帮助你打造视觉惊艳的 Qt 应用界面,这是 图形界面开发 中提升用户体验的关键技巧。
一、QPen 与 QBrush 的关系:不只是颜色
1.1 QPen 的构造与设置
QPen 的常用构造方式如下:
QPen pen(Qt::blue, 2); // 颜色 + 宽度
pen.setColor(Qt::red);
pen.setWidth(3);
但一个常被忽略的关键方法是:
void QPen::setBrush(const QBrush &brush);
一旦为 QPen 设置了 brush,setColor() 方法所设置的颜色将被忽略,画笔的最终表现完全由 brush 决定。
✅ 核心原理:
当 QPen 的 brush().style() != Qt::NoBrush 时,绘制的线条将使用该 brush 进行纹理填充,而非使用单一颜色。
1.2 QBrush 支持的丰富样式
QBrush 可以轻松定义为多种样式:
- 纯色(
Qt::red)
- 线性渐变(
QLinearGradient)
- 径向渐变(
QRadialGradient)
- 锥形渐变(
QConicalGradient)
- 图像纹理(
QPixmap)
- 自定义图案(
QImage)
这些样式都可以直接赋予 QPen,从而丰富线条的视觉效果。
二、基础示例:用渐变画笔绘制线条
2.1 绘制线性渐变线条
void paintEvent(QPaintEvent *) override {
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
// 创建线性渐变(从左到右)
QLinearGradient gradient(0, 0, width(), 0);
gradient.setColorAt(0.0, Qt::red);
gradient.setColorAt(0.5, Qt::yellow);
gradient.setColorAt(1.0, Qt::green);
// 创建画笔并设置 brush
QPen pen;
pen.setBrush(gradient);
pen.setWidth(8);
pen.setCapStyle(Qt::RoundCap);
painter.setPen(pen);
painter.drawLine(50, 100, width() - 50, 100); // 水平线
}
🌈 效果:一条从红色渐变到黄色,再过渡到绿色的水平线条。
2.2 绘制径向渐变圆形边框
QRect rect(100, 100, 200, 200);
QRadialGradient radial(rect.center(), rect.width()/2);
radial.setColorAt(0.0, Qt::white);
radial.setColorAt(1.0, Qt::darkBlue);
QPen pen;
pen.setBrush(radial);
pen.setWidth(6);
painter.setPen(pen);
painter.setBrush(Qt::NoBrush); // 确保不填充内部
painter.drawEllipse(rect);
🔵 效果:一个中心明亮、边缘为深蓝色的发光圆环。
三、高级实战:渐变进度条
传统的单色进度条略显单调,使用彩虹渐变能显著提升视觉体验。
3.1 自定义 RainbowProgressBar 类
// rainbowprogressbar.h
#include <QWidget>
#include <QColor>
class RainbowProgressBar : public QWidget {
Q_OBJECT
Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged)
public:
explicit RainbowProgressBar(QWidget *parent = nullptr);
int value() const { return m_value; }
void setValue(int val) {
m_value = qBound(0, val, 100);
update();
emit valueChanged(m_value);
}
signals:
void valueChanged(int);
protected:
void paintEvent(QPaintEvent *) override;
private:
int m_value = 0;
};
3.2 实现渐变绘制逻辑
// rainbowprogressbar.cpp
#include “rainbowprogressbar.h"
#include <QPainter>
#include <QLinearGradient>
RainbowProgressBar::RainbowProgressBar(QWidget *parent) : QWidget(parent) {
setMinimumHeight(20);
}
void RainbowProgressBar::paintEvent(QPaintEvent *) {
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
// 背景:浅灰色槽
QRect groove = rect().adjusted(2, 2, -2, -2);
painter.fillRect(groove, QColor(220, 220, 220));
// 计算进度区域
int progressWidth = groove.width() * m_value / 100;
QRect progressRect(groove.left(), groove.top(), progressWidth, groove.height());
if (progressWidth > 0) {
// 创建彩虹渐变(0%~100% 映射到色相 0~360)
QLinearGradient rainbow(progressRect.left(), 0, progressRect.right(), 0);
rainbow.setColorAt(0.0, QColor::fromHsvF(0.0, 1.0, 1.0)); // 红
rainbow.setColorAt(0.16, QColor::fromHsvF(0.16, 1.0, 1.0)); // 黄
rainbow.setColorAt(0.33, QColor::fromHsvF(0.33, 1.0, 1.0)); // 绿
rainbow.setColorAt(0.5, QColor::fromHsvF(0.5, 1.0, 1.0)); // 青
rainbow.setColorAt(0.66, QColor::fromHsvF(0.66, 1.0, 1.0)); // 蓝
rainbow.setColorAt(0.83, QColor::fromHsvF(0.83, 1.0, 1.0)); // 紫
rainbow.setColorAt(1.0, QColor::fromHsvF(1.0, 1.0, 1.0)); // 回红
QPen pen;
pen.setBrush(rainbow);
pen.setWidth(groove.height());
pen.setCapStyle(Qt::RoundCap);
// 绘制渐变进度条(作为“粗线”)
int centerY = groove.center().y();
painter.setPen(pen);
painter.drawLine(progressRect.left(), centerY, progressRect.right(), centerY);
}
}
3.3 使用示例
// mainwindow.cpp
RainbowProgressBar *bar = new RainbowProgressBar(this);
bar->setValue(75);
layout->addWidget(bar);
🌈 效果:一个随进度变化而呈现彩虹色的进度条,视觉效果远超单色进度条。
四、炫彩文字:用渐变画笔绘制文本轮廓
QPainter::drawText() 默认使用 pen.color() 来填充文字。但若想实现文字本身的渐变效果,该如何操作?
方法:先用渐变画笔描边,再用背景色填充内部
void drawGradientText(QPainter &painter, const QString &text, const QPoint &pos) {
QFont font("Arial", 48, QFont::Bold);
painter.setFont(font);
// 1. 创建渐变画笔(用于描边)
QLinearGradient textGrad(pos.x(), pos.y(), pos.x() + 300, pos.y());
textGrad.setColorAt(0, Qt::cyan);
textGrad.setColorAt(1, Qt::magenta);
QPen outlinePen;
outlinePen.setBrush(textGrad);
outlinePen.setWidth(2);
outlinePen.setJoinStyle(Qt::RoundJoin);
// 2. 先绘制带渐变边框的文字
painter.setPen(outlinePen);
painter.drawText(pos, text);
// 3. (可选)再用白色填充内部,制造“空心+渐变边”效果
painter.setPen(Qt::white);
painter.drawText(pos, text);
}
💡 技巧:通过两次绘制(先描边后填充),可以轻松实现渐变轮廓搭配纯色填充的混合视觉效果。
五、动态效果:霓虹呼吸灯边框
结合 QPropertyAnimation,我们可以让渐变边框产生“呼吸”般的动态效果,这不仅是UI技巧,也涉及动态图形渲染的 算法思想。
// 在 widget 中
QConicalGradient glow(center, 0, center.x(), center.y());
glow.setColorAt(0, QColor(0, 200, 255, 200));
glow.setColorAt(0.5, QColor(255, 100, 255, 100));
glow.setColorAt(1, QColor(0, 200, 255, 200));
QPen pen;
pen.setBrush(glow);
pen.setWidth(8 + sin(m_phase) * 3); // 动态宽度
painter.setPen(pen);
painter.drawEllipse(center, 80, 80);
// 每 50ms 更新 m_phase += 0.2
✨ 效果:一个不断脉动变化的霓虹光环,极具科技感与动态美。
六、注意事项与性能优化
6.1 抗锯齿必须开启
使用渐变画笔时,务必开启抗锯齿,否则可能出现明显的锯齿或色带现象:
painter.setRenderHint(QPainter::Antialiasing, true);
6.2 避免在高频重绘中重复创建 QBrush
为了提高性能,应将 QGradient 或 QBrush 缓存为成员变量,避免在每次 paintEvent 中重复创建:
class MyWidget : public QWidget {
QLinearGradient m_cachedGradient; // 成员变量
mutable bool m_gradientDirty = true;
};
6.3 文字渐变的局限性
drawText() 方法本身不支持直接使用画笔的 brush 来填充文字内部。
- 对于更复杂的文字特效,建议考虑使用
QGraphicsEffect 或将文字导出为 QPicture 进行处理。
七、总结:QPen + QBrush = 无限可能
| 传统做法 |
升级方案 |
视觉提升 |
pen.setColor(Qt::blue) |
pen.setBrush(QLinearGradient(...)) |
单色 → 渐变 |
| 静态边框 |
动态渐变边框 |
死板 → 活泼 |
| 普通进度条 |
彩虹进度条 |
乏味 → 吸引 |
💡 记住:
QPen 不只是“颜色”,它是“纹理”的载体。
只要充分发挥想象力,就能利用 QBrush 赋予线条新的生命——无论是在数据可视化、游戏 UI 还是创意艺术项目中,都能大放异彩。
附录:完整可运行示例
// main.cpp
#include <QApplication>
#include <QWidget>
#include <QPainter>
#include <QTimer>
class GradientDemo : public QWidget {
protected:
void paintEvent(QPaintEvent*) override {
QPainter p(this);
p.setRenderHint(QPainter::Antialiasing);
// 渐变圆环
QRect r(50, 50, 200, 200);
QRadialGradient grad(r.center(), 120);
grad.setColorAt(0, Qt::yellow);
grad.setColorAt(1, Qt::red);
QPen pen;
pen.setBrush(grad);
pen.setWidth(10);
p.setPen(pen);
p.setBrush(Qt::NoBrush);
p.drawEllipse(r);
// 渐变文字
QLinearGradient textGrad(0, 0, 300, 0);
textGrad.setColorAt(0, Qt::cyan);
textGrad.setColorAt(1, Qt::magenta);
pen.setBrush(textGrad);
pen.setWidth(1);
p.setPen(pen);
p.setFont(QFont("Arial", 24, QFont::Bold));
p.drawText(50, 300, “Gradient Text!");
}
};
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
GradientDemo w;
w.resize(400, 400);
w.show();
return a.exec();
}
编译并运行上述代码,你将看到一个从黄色渐变到红色的发光圆环,以及一行从青色渐变到品红色的文字——所有这些炫酷的效果,都源于对 QPen::setBrush() 方法的巧妙运用。