在 Qt4 中绘图
最后修改于 2023 年 10 月 18 日
在本 Qt4 C++ 编程教程中,我们将进行一些绘图。
当我们在 Qt4 中进行一些绘图时,QPainter
类是必不可少的。 绘图是在对 paintEvent
方法的响应中使用 QPainter
类完成的。
线条
在第一个示例中,我们在窗口的客户区上绘制一些线条。
#pragma once #include <QWidget> class Lines : public QWidget { public: Lines(QWidget *parent = 0); protected: void paintEvent(QPaintEvent *event); void drawLines(QPainter *qp); };
这是头文件。
#include <QPainter> #include "lines.h" Lines::Lines(QWidget *parent) : QWidget(parent) { } void Lines::paintEvent(QPaintEvent *e) { Q_UNUSED(e); QPainter qp(this); drawLines(&qp); } void Lines::drawLines(QPainter *qp) { QPen pen(Qt::black, 2, Qt::SolidLine); qp->setPen(pen); qp->drawLine(20, 40, 250, 40); pen.setStyle(Qt::DashLine); qp->setPen(pen); qp->drawLine(20, 80, 250, 80); pen.setStyle(Qt::DashDotLine); qp->setPen(pen); qp->drawLine(20, 120, 250, 120); pen.setStyle(Qt::DotLine); qp->setPen(pen); qp->drawLine(20, 160, 250, 160); pen.setStyle(Qt::DashDotDotLine); qp->setPen(pen); qp->drawLine(20, 200, 250, 200); QVector<qreal> dashes; qreal space = 4; dashes << 1 << space << 5 << space; pen.setStyle(Qt::CustomDashLine); pen.setDashPattern(dashes); qp->setPen(pen); qp->drawLine(20, 240, 250, 240); }
我们在窗口上绘制六条线;每条线都有不同的笔样式。
void Lines::paintEvent(QPaintEvent *e) { Q_UNUSED(e); QPainter qp(this); drawLines(&qp); }
当更新小部件时,会调用 paintEvent
。 我们在这里创建 QPainter
对象并进行绘图。 由于我们没有使用 QPaintEvent
对象,因此我们使用 Q_UNUSED
宏来抑制编译器警告。 真正的绘图被委托给 drawLines
方法。
QPen pen(Qt::black, 2, Qt::SolidLine); qp->setPen(pen);
我们创建一个 QPen
对象。 笔是实心的,2 像素粗,黑色。 笔用于绘制线条和形状的轮廓。 笔使用 setPen
方法设置为 painter 对象。
qp->drawLine(20, 40, 250, 40);
drawLine
方法绘制一条线。 这四个参数是窗口上两个点的坐标。
pen.setStyle(Qt::DashLine);
QPen
线的 setStyle
方法设置笔样式 - Qt::DashLine
。
#include <QApplication> #include "lines.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); Lines window; window.resize(280, 270); window.setWindowTitle("Lines"); window.show(); return app.exec(); }
这是主文件。

颜色
颜色是表示红、绿和蓝 (RGB) 强度值组合的对象。 有效的 RGB 值在 0 到 255 范围内。在下面的示例中,我们绘制了九个用九种不同颜色填充的矩形。
#pragma once #include <QWidget> class Colours : public QWidget { Q_OBJECT public: Colours(QWidget *parent = 0); protected: void paintEvent(QPaintEvent *); void drawColouredRectangles(QPainter &); };
这是头文件。
#include <QPainter> #include "colours.h" Colours::Colours(QWidget *parent) : QWidget(parent) { } void Colours::paintEvent(QPaintEvent *e) { Q_UNUSED(e); QPainter qp(this); drawColouredRectangles(qp); } void Colours::drawColouredRectangles(QPainter &qp) { qp.setPen(QColor("#d4d4d4")); qp.setBrush(QBrush("#c56c00")); qp.drawRect(10, 15, 90, 60); qp.setBrush(QBrush("#1ac500")); qp.drawRect(130, 15, 90, 60); qp.setBrush(QBrush("#539e47")); qp.drawRect(250, 15, 90, 60); qp.setBrush(QBrush("#004fc5")); qp.drawRect(10, 105, 90, 60); qp.setBrush(QBrush("#c50024")); qp.drawRect(130, 105, 90, 60); qp.setBrush(QBrush("#9e4757")); qp.drawRect(250, 105, 90, 60); qp.setBrush(QBrush("#5f3b00")); qp.drawRect(10, 195, 90, 60); qp.setBrush(QBrush("#4c4c4c")); qp.drawRect(130, 195, 90, 60); qp.setBrush(QBrush("#785f36")); qp.drawRect(250, 195, 90, 60); }
我们绘制了九个填充不同颜色的矩形。 矩形的轮廓是灰色的。
qp.setBrush(QBrush("#c56c00")); qp.drawRect(10, 15, 90, 60);
QBrush
类定义了 QPainter
绘制的形状的填充图案。 drawRect
方法绘制一个矩形。 它绘制一个左上角在 x, y 点且具有给定宽度和高度的矩形。 我们使用十六进制表示法来指定颜色值。
#include <QApplication> #include "colours.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); Colours window; window.resize(360, 280); window.setWindowTitle("Colours"); window.show(); return app.exec(); }
这是主文件。

图案
下面的编程代码示例与前面的示例类似。 这次我们用各种预定义的图案填充矩形。
#pragma once #include <QWidget> class Patterns : public QWidget { public: Patterns(QWidget *parent = 0); protected: void paintEvent(QPaintEvent *); void drawRectangles(QPainter &); };
头文件。
#include <QApplication> #include <QPainter> #include "patterns.h" Patterns::Patterns(QWidget *parent) : QWidget(parent) { } void Patterns::paintEvent(QPaintEvent *e) { Q_UNUSED(e); QPainter qp(this); drawRectangles(qp); } void Patterns::drawRectangles(QPainter &qp) { qp.setPen(Qt::NoPen); qp.setBrush(Qt::HorPattern); qp.drawRect(10, 15, 90, 60); qp.setBrush(Qt::VerPattern); qp.drawRect(130, 15, 90, 60); qp.setBrush(Qt::CrossPattern); qp.drawRect(250, 15, 90, 60); qp.setBrush(Qt::Dense7Pattern); qp.drawRect(10, 105, 90, 60); qp.setBrush(Qt::Dense6Pattern); qp.drawRect(130, 105, 90, 60); qp.setBrush(Qt::Dense5Pattern); qp.drawRect(250, 105, 90, 60); qp.setBrush(Qt::BDiagPattern); qp.drawRect(10, 195, 90, 60); qp.setBrush(Qt::FDiagPattern); qp.drawRect(130, 195, 90, 60); qp.setBrush(Qt::DiagCrossPattern); qp.drawRect(250, 195, 90, 60); }
我们用各种画笔图案绘制了九个矩形。
qp.setBrush(Qt::HorPattern); qp.drawRect(10, 15, 90, 60);
我们绘制一个具有特定图案的矩形。 Qt::HorPattern
是一个用于创建水平线图案的常量。
#include <QApplication> #include "patterns.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); Patterns window; window.resize(350, 280); window.setWindowTitle("Patterns"); window.show(); return app.exec(); }
这是主文件。

甜甜圈
在下面的示例中,我们创建一个甜甜圈形状。
#pragma once #include <QWidget> class Donut : public QWidget { Q_OBJECT public: Donut(QWidget *parent = 0); protected: void paintEvent(QPaintEvent *); void drawDonut(QPainter &); };
这是头文件。
#include <QApplication> #include <QPainter> #include "donut.h" Donut::Donut(QWidget *parent) : QWidget(parent) { } void Donut::paintEvent(QPaintEvent *e) { Q_UNUSED(e); QPainter qp(this); drawDonut(qp); } void Donut::drawDonut(QPainter &qp) { qp.setPen(QPen(QBrush("#535353"), 0.5)); qp.setRenderHint(QPainter::Antialiasing); int h = height(); int w = width(); qp.translate(QPoint(w/2, h/2)); for (qreal rot=0; rot < 360.0; rot+=5.0 ) { qp.drawEllipse(-125, -40, 250, 80); qp.rotate(5.0); } }
“甜甜圈” 是一种高级的几何形状,类似于这种食物。 我们通过绘制 72 个旋转的椭圆来创建它。
qp.setRenderHint(QPainter::Antialiasing);
我们以抗锯齿模式进行绘图。 渲染将具有更高的质量。
int h = height(); int w = width(); qp.translate(QPoint(w/2, h/2));
这些行将坐标系的起点移到窗口的中间。 默认情况下,它位于 0, 0 点。 换句话说,在窗口的左上角。 通过移动坐标系,绘图会容易得多。
for (qreal rot=0; rot < 360.0; rot+=5.0 ) { qp.drawEllipse(-125, -40, 250, 80); qp.rotate(5.0); }
在这个 for 循环中,我们绘制 72 个旋转的椭圆。
#include <QApplication> #include "donut.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); Donut window; window.resize(350, 280); window.setWindowTitle("Donut"); window.show(); return app.exec(); }
这是主文件。
形状
Qt4 绘图 API 可以绘制各种形状。 以下编程代码示例展示了其中的一些。
#pragma once #include <QWidget> class Shapes : public QWidget { Q_OBJECT public: Shapes(QWidget *parent = 0); protected: void paintEvent(QPaintEvent *e); };
这是头文件。
#include <QApplication> #include <QPainter> #include <QPainterPath> #include "shapes.h" Shapes::Shapes(QWidget *parent) : QWidget(parent) { } void Shapes::paintEvent(QPaintEvent *e) { Q_UNUSED(e); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.setPen(QPen(QBrush("#888"), 1)); painter.setBrush(QBrush(QColor("#888"))); QPainterPath path1; path1.moveTo(5, 5); path1.cubicTo(40, 5, 50, 50, 99, 99); path1.cubicTo(5, 99, 50, 50, 5, 5); painter.drawPath(path1); painter.drawPie(130, 20, 90, 60, 30*16, 120*16); painter.drawChord(240, 30, 90, 60, 0, 16*180); painter.drawRoundRect(20, 120, 80, 50); QPolygon polygon({QPoint(130, 140), QPoint(180, 170), QPoint(180, 140), QPoint(220, 110), QPoint(140, 100)}); painter.drawPolygon(polygon); painter.drawRect(250, 110, 60, 60); QPointF baseline(20, 250); QFont font("Georgia", 55); QPainterPath path2; path2.addText(baseline, font, "Q"); painter.drawPath(path2); painter.drawEllipse(140, 200, 60, 60); painter.drawEllipse(240, 200, 90, 60); }
我们绘制了九个不同的形状。
QPainterPath path1; path1.moveTo(5, 5); path1.cubicTo(40, 5, 50, 50, 99, 99); path1.cubicTo(5, 99, 50, 50, 5, 5); painter.drawPath(path1);
QPainterPath
是一个用于创建复杂形状的对象。 我们使用它来绘制贝塞尔曲线。
painter.drawPie(130, 20, 90, 60, 30*16, 120*16); painter.drawChord(240, 30, 90, 60, 0, 16*180); painter.drawRoundRect(20, 120, 80, 50);
这些代码行绘制了一个扇形、一个弦和一个圆角矩形。
QPolygon polygon({QPoint(130, 140), QPoint(180, 170), QPoint(180, 140), QPoint(220, 110), QPoint(140, 100)}); painter.drawPolygon(polygon);
在这里,我们使用 drawPolygon
方法绘制一个多边形。 多边形由五个点组成。
QPointF baseline(20, 250); QFont font("Georgia", 55); QPainterPath path2; path2.addText(baseline, font, "Q"); painter.drawPath(path2);
Qt4 允许基于字体字符创建路径。
painter.drawEllipse(140, 200, 60, 60); painter.drawEllipse(240, 200, 90, 60);
drawEllipse
绘制一个椭圆和一个圆。 圆是椭圆的一种特殊情况。 参数是矩形开始的 x 和 y 坐标以及椭圆的边界矩形的宽度和高度。
#include <QApplication> #include "shapes.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); Shapes window; window.resize(350, 280); window.setWindowTitle("Shapes"); window.show(); return app.exec(); }
这是该示例的主文件。

渐变
在计算机图形学中,渐变是从亮到暗或从一种颜色到另一种颜色的平滑混合。 在 2D 绘图程序和绘画程序中,渐变用于创建彩色背景和特殊效果,以及模拟光和阴影。
下面的代码示例展示了如何创建线性渐变。
#pragma once #include <QWidget> class Gradient : public QWidget { public: Gradient(QWidget *parent = 0); protected: void paintEvent(QPaintEvent *e); };
这是头文件。
#include <QApplication> #include <QPainter> #include "gradients.h" Gradient::Gradient(QWidget *parent) : QWidget(parent) { } void Gradient::paintEvent(QPaintEvent *e) { Q_UNUSED(e); QPainter painter(this); QLinearGradient grad1(0, 20, 0, 110); grad1.setColorAt(0.1, Qt::black); grad1.setColorAt(0.5, Qt::yellow); grad1.setColorAt(0.9, Qt::black); painter.fillRect(20, 20, 300, 90, grad1); QLinearGradient grad2(0, 55, 250, 0); grad2.setColorAt(0.2, Qt::black); grad2.setColorAt(0.5, Qt::red); grad2.setColorAt(0.8, Qt::black); painter.fillRect(20, 140, 300, 100, grad2); }
在代码示例中,我们绘制了两个矩形并用线性渐变填充它们。
QLinearGradient grad1(0, 20, 0, 110);
QLinearGradient
构造一个线性渐变,其插值区域在作为参数提供的两点之间。
grad1.setColorAt(0.1, Qt::black); grad1.setColorAt(0.5, Qt::yellow); grad1.setColorAt(0.9, Qt::black);
渐变中的颜色是使用停靠点定义的。 setColorAt
在给定位置创建具有给定颜色的停靠点。
painter.fillRect(20, 20, 300, 90, grad1);
我们用渐变填充矩形。
#include <QApplication> #include "gradients.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); Gradient window; window.resize(350, 260); window.setWindowTitle("Gradients"); window.show(); return app.exec(); }
这是主文件。

径向渐变
径向渐变是两种颜色或颜色阴影在两个圆之间的混合。
#pragma once #include <QWidget> class RadialGradient : public QWidget { public: RadialGradient(QWidget *parent = 0); protected: void paintEvent(QPaintEvent *e); };
这是头文件。
#include <QApplication> #include <QPainter> #include "radial_gradient.h" RadialGradient::RadialGradient(QWidget *parent) : QWidget(parent) { } void RadialGradient::paintEvent(QPaintEvent *e) { Q_UNUSED(e); QPainter painter(this); int h = height(); int w = width(); QRadialGradient grad1(w/2, h/2, 80); grad1.setColorAt(0, QColor("#032E91")); grad1.setColorAt(0.3, Qt::white); grad1.setColorAt(1, QColor("#032E91")); painter.fillRect(0, 0, w, h, grad1); }
该示例创建一个径向渐变;渐变从窗口的中心向外扩散。
QRadialGradient grad1(w/2, h/2, 80);
QRadialGradient
创建一个径向渐变;它在焦点和围绕它的圆上的端点之间插值颜色。 参数是圆的中心点的坐标及其半径。 焦点位于圆的中心。
grad1.setColorAt(0, QColor("#032E91")); grad1.setColorAt(0.3, Qt::white); grad1.setColorAt(1, QColor("#032E91"));
setColorAt
方法定义了彩色停靠点。
painter.fillRect(0, 0, w, h, grad1);
整个窗口区域都填充了径向渐变。
#include <QApplication> #include "radial_gradient.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); RadialGradient window; window.resize(300, 250); window.setWindowTitle("Radial gradient"); window.show(); return app.exec(); }
这是主文件。

喷雾
在本 C++ Qt4 教程章节的最后一个示例中,我们创建了一个喷雾效果。 该示例显示了一个从某个点逐渐淡出的增长的居中文本。 这是一种非常常见的效果,您经常可以在网络上的 Flash 动画中看到。
#pragma once #include <QWidget> class Puff : public QWidget { Q_OBJECT public: Puff(QWidget *parent = 0); protected: void paintEvent(QPaintEvent *event); void timerEvent(QTimerEvent *event); private: int x; qreal opacity; int timerId; };
在头文件中,我们定义了两个事件处理程序:绘制事件处理程序和计时器处理程序。
#include <QPainter> #include <QTimer> #include <QTextStream> #include "puff.h" Puff::Puff(QWidget *parent) : QWidget(parent) { x = 1; opacity = 1.0; timerId = startTimer(15); } void Puff::paintEvent(QPaintEvent *e) { Q_UNUSED(e); QPainter painter(this); QTextStream out(stdout); QString text = "ZetCode"; painter.setPen(QPen(QBrush("#575555"), 1)); QFont font("Courier", x, QFont::DemiBold); QFontMetrics fm(font); int textWidth = fm.width(text); painter.setFont(font); if (x > 10) { opacity -= 0.01; painter.setOpacity(opacity); } if (opacity <= 0) { killTimer(timerId); out << "timer stopped" << endl; } int h = height(); int w = width(); painter.translate(QPoint(w/2, h/2)); painter.drawText(-textWidth/2, 0, text); } void Puff::timerEvent(QTimerEvent *e) { Q_UNUSED(e); x += 1; repaint(); }
这是 puff.cpp
文件。
Puff::Puff(QWidget *parent) : QWidget(parent) { x = 1; opacity = 1.0; timerId = startTimer(15); }
在构造函数中,我们启动计时器。 每 15 毫秒生成一个计时器事件。
void Puff::timerEvent(QTimerEvent *e) { Q_UNUSED(e); x += 1; repaint(); }
在 timerEvent
中,我们增加字体大小并重绘小部件。
if (x > 10) { opacity -= 0.01; painter.setOpacity(opacity); }
如果字体大小大于 10 磅,我们逐渐降低不透明度;文本开始淡出。
if (opacity <= 0) { killTimer(timerId); out << "timer stopped" << endl; }
如果文本完全消失,我们会停止计时器。
#include <QApplication> #include "puff.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); Puff window; window.resize(350, 280); window.setWindowTitle("Puff"); window.show(); return app.exec(); }
这是主文件。
本章是关于在 Qt4 中绘图的。