点击上方蓝字关注我们9.3 QPainter图形绘制 Qt绘图主要用到QPainter类,QPainter类提供了许多高度优化的函数去做大部分的GUI绘制工作。它可以画简单的线到复杂的形状,通常情况下,QPainter是在widget的painter绘图事件函数中使用。绘图的设备通常是主部件,也可以是QLabel部件或QTextEdit部件,通过一定的算法实现可以绘制出很漂亮的图形或我们需要的图形。 绘制时需要先定义一个QPainter类对象,绘制可以选择Qpen(画笔)、QBrush(画刷)。使用QPen写文本时还可以指定字体(QFont类)。 下面是QT帮助文档提供的一个示例程序,绘制一个QT文本: void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); painter.setPen(Qt::blue); painter.setFont(QFont("Arial", 80)); painter.drawText(rect(), Qt::AlignCenter, "Qt"); }
显示效果如下: 绘图的时候,需要重载QWidget类的paintEvent ( QPaintEvent * )事件,函数原型如下: void QWidget::paintEvent(QPaintEvent *event)
该函数是受保护的虚函数,是绘制事件的函数,可以在派生类中被重新实现来接受绘制事件。所以使用时要现在类中声明paintEvent函数,然后在函数定义中实现图像的绘制。 声明paintEvent示例: class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); private: Ui::Widget *ui; void paintEvent(QPaintEvent *event); //声明paintEvent函数 };
9.3.1 QPainter相关函数介绍 1. 构造QPainter对象 QPainter() QPainter(QPaintDevice *device)
Qpainter的构造函数比较简单,其中形参QPaintDevice类是绘图设备的基类。QPaintDevice的派生类:QImage、 QOpenGLPaintDevice、 QPagedPaintDevice、 QPaintDeviceWindow、QPicture、QPixmap等。 下面示例代码使用QPixmap加载图片,通过Qpainter在QPixmap加载的图片上绘上一个QT字符串: QPixmap pixmap("E:/1.png");//加载图片 QPainter painter(&pixmap);//构建QPainter绘图对象 painter.setPen(Qt::blue); painter.setFont(QFont("Arial", 50)); painter.drawText(pixmap.rect(), Qt::AlignCenter, "Qt"); pixmap.save("E:/2.png");
效果图: 图9-3-1 绘制字符串效果示例 2. 开始与结束绘图 bool QPainter::begin(QPaintDevice *device) //开始绘图 bool QPainter::end() //结束绘图
调用end()函数可以释放绘图占用的所有资源。我们通常不需要调用end()函数,因为它是由析构函数自动调用。 (1) 使用begin和end函数绘图方式: void Widget::paintEvent(QPaintEvent *) { QPainter p; p.begin(this); /*编写绘图代码*/ p.end(); }
(2)不使用begin和end函数绘图方式 void Widget::paintEvent(QPaintEvent *) { QPainter p(this); /*编写绘图代码*/ }
3. 设置画笔样式 const QPen &pen() const; 获取画笔QPen void setPen(const QColor &color); 设置画笔颜色 void setPen(const QPen &pen); 设置画笔(复制已存在的画笔对象) void setPen(Qt::PenStyle style); 设置画笔的样式
形参中的QPen类定义了QPainter类绘制一个线条和一个轮廓的形状,QColor类定义了颜色的表示方法,Qt::PenStyle style是QPainter定义的画笔样式枚举。 Qt::PenStyle style枚举值如下图: 图9-3-2 QPainter画笔样式 设置画笔样式示例: void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); QPen pen; //创建一个默认的画笔 pen.setStyle(Qt::DashDotLine);//设置样式 pen.setWidth(10); //设置宽度 pen.setBrush(Qt::green); //设置画刷颜色 pen.setCapStyle(Qt::RoundCap);//设置笔帽样式 pen.setJoinStyle(Qt::RoundJoin);//设置连接点的样式 painter.setPen(pen); painter.drawEllipse(QRectF(40.0,40.0, 100.0, 100.0)); //绘制椭圆 }
图9-3-3 画笔样式设置效果 4. 设置画笔透明度 void QPainter::setOpacity(qreal opacity) //设置透明度 qreal QPainter::opacity() const //获取透明度
透明度的设置范围在0.0 到1.0之间。0.0表示完全透明,1.0表示不透明。该透明度适用于所有的画图设备。 5. 绘制文本 void QPainter::drawText(const QPointF &position, const QString &text) void QPainter::drawText(const QPoint &position, const QString &text) void QPainter::drawText(int x, int y, const QString &text) void QPainter::drawText(const QRectF &rectangle, int flags, const QString &text, QRectF *boundingRect = Q_NULLPTR)
drawText函数用来在指定位置绘制文本字符串,可是使用setFont()函数设置文本的字体。其中flags标志用于设置文本的对齐方式。比如:左对齐Qt::AlignLeft、右对齐Qt::AlignRight、中间对齐Qt::AlignJustify等等。 给图片加水印示例: QPixmap pixmap("E:/qt.jpg");//加载图片 QPainter painter(&pixmap); //构建画布 painter.setPen(Qt::blue); painter.setFont(QFont("宋体", 20)); painter.drawText(0,0,pixmap.width(),50,Qt::AlignLeft, "时间水印:2016/11/20"); pixmap.save("E:/newqt.png");
图片绘制字符串后显示效果如下: 6. 画点相关函数 void QPainter::drawPoint(int x, int y) void QPainter::drawPoint(const QPointF &position) void QPainter::drawPoint(const QPoint &position) void QPainter::drawPoints(const QPointF *points, int pointCount) void QPainter::drawPoints(const QPolygonF &points) void QPainter::drawPoints(const QPoint *points, int pointCount) void QPainter::drawPoints(const QPolygon &points)
drawPoint函数用于在画布的指定位置绘制一个点,形参指定点绘制的位置。drawPoints函数用于在画布上绘制多个点,通过指定点坐标数组来绘制。其中QPointF类代表小数点精度,QPoint类代表整型精度。 一次画多个点示例: void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); QPen pen; //创建一个默认的画笔 pen.setStyle(Qt::DashDotLine);//设置样式 pen.setWidth(10);//设置宽度 pen.setBrush(Qt::green);//设置画刷 painter.setPen(pen); QPoint poin[]={ {20,10}, {30,10}, {40,10}, }; painter.drawPoints(poin,3);//根据数组数据绘制点 }
7. 画线相关函数 void QPainter::drawLine(const QLineF &line) void QPainter::drawLine(const QLine &line) void QPainter::drawLine(int x1, int y1, int x2, int y2) void QPainter::drawLine(const QPointF &p1, const QPointF &p2) void QPainter::drawLine(const QPoint &p1, const QPoint &p2) void QPainter::drawLines(const QLineF *lines, int lineCount) void QPainter::drawLines(const QVector<QLineF> &lines) void QPainter::drawLines(const QPointF *pointPairs, int lineCount) void QPainter::drawLines(const QVector<QPointF> &pointPairs) void QPainter::drawLines(const QLine *lines, int lineCount) void QPainter::drawLines(const QVector<QLine> &lines) void QPainter::drawLines(const QPoint *pointPairs, int lineCount) void QPainter::drawLines(const QVector<QPoint> &pointPairs)
drawLine函数用于在指定位置绘制一条线,形参用于指定线绘制的位置。drawLines函数用于在画布上绘制多条线,通过指定线条的坐标数组来绘制。绘制线条时,前两个(x,y)坐标参数表示线的起点位置,后两个(x1,y1)坐标参数指定线的结束位置。 使用drawLines函数绘制矩形示例: void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); QPen pen; //创建一个默认的画笔 pen.setStyle(Qt::SolidLine);//设置样式 pen.setWidth(20);//设置宽度 pen.setBrush(Qt::green);//设置画刷 painter.setPen(pen); QVector<QLineF> linelist;//构造存放线段位置的列表 linelist.append(QLineF(20,20,100,20)); linelist.append(QLineF(100,20,100,100)); linelist.append(QLineF(20,20,20,100)); linelist.append(QLineF(20,100,100,100)); // painter.drawLine(10,10,50,10);//绘制一条线 painter.drawLines(linelist);//绘制多条线 }
图9-3-4 绘制多条线效果图 8. 绘制矩形相关函数 void QPainter::drawRect(const QRectF &rectangle) void QPainter::drawRect(int x, int y, int width, int height) void QPainter::drawRect(const QRect &rectangle) void QPainter::drawRects(const QRectF *rectangles, int rectCount) void QPainter::drawRects(const QVector<QRectF> &rectangles) void QPainter::drawRects(const QRect *rectangles, int rectCount) void QPainter::drawRects(const QVector<QRect> &rectangles)
drawRect函数用于绘制单个矩形,drawRects函数用于绘制多个矩形。绘制矩形需要填4个参数,前两个参数指定矩形左上角点坐标位置(x,y),后两个参数指定矩形右下角点坐标位置(x1,y1)。 绘制矩形示例: void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); painter.drawRect(10,20,80,60); }
9. 绘制椭圆形 void QPainter::drawEllipse(const QRectF &rectangle) void QPainter::drawEllipse(const QRect &rectangle) void QPainter::drawEllipse(int x, int y, int width, int height) void QPainter::drawEllipse(const QPointF ¢er, qreal rx, qreal ry) void QPainter::drawEllipse(const QPoint ¢er, int rx, int ry)
drawEllipse函数用于在一个矩形框架内绘制椭圆。绘制椭圆填入的参数与绘制矩形类似,可以将绘制椭圆比作绘制矩形去理解形参。参数模型图如下所示: 绘制圆和椭圆示例: void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); QPen pen; pen.setStyle(Qt::SolidLine); pen.setWidth(2); pen.setBrush(Qt::green); painter.setPen(pen); painter.drawEllipse(10,10,100,100); //绘制圆 painter.drawEllipse(120,10,50,100); //绘制椭圆 }
图9-3-5 绘制圆和椭圆效果 10. 绘制弧形 void QPainter::drawArc(const QRectF &rectangle, int startAngle, int spanAngle) void QPainter::drawArc(const QRect &rectangle, int startAngle, int spanAngle) void QPainter::drawArc(int x, int y, int width, int height, int startAngle, int spanAngle)
drawArc函用于在一个矩形框架内绘制弧形。以drawArc(int x, int y, int width, int height, int startAngle, int spanAngle)函数为例,其中前4个参数用来指定矩形框架的尺寸,startAngle表示起始角,spanAngle表示跨度角。 注意:上面提到的起始角和跨度角的角度值是以1/16为单位的,在画弧时1°用16表示。 绘制弧形示例: void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); QPen pen; pen.setWidth(2); painter.setPen(pen); QRectF rectangle(10.0, 20.0, 150.0, 100.0); int startAngle = 30 * 16; //开始角度30° int spanAngle = 140 * 16;//跨度140° painter.drawArc(rectangle, startAngle, spanAngle); }
图9-3-6 绘制弧形效果 11. 绘制扇形 void QPainter::drawPie(const QRectF &rectangle, int startAngle, int spanAngle) void QPainter::drawPie(int x, int y, int width, int height, int startAngle, int spanAngle) void QPainter::drawPie(const QRect &rectangle, int startAngle, int spanAngle)
绘制扇形drawPie与绘制弧形drawArc函数填入的参数类似,只是绘制扇形时,弧形的两边会连接到圆心。 绘制扇形示例: void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); QPen pen; pen.setWidth(5); painter.setPen(pen); QRectF rectangle(10.0, 20.0, 80.0, 60.0); int startAngle = 30 * 16; int spanAngle = 120 * 16; painter.drawPie(rectangle, startAngle, spanAngle); }
图9-3-7 绘制扇形效果 12. 绘制半圆形状 void QPainter:: drawChord(const QRectF &rectangle, int startAngle, int spanAngle) void QPainter::drawChord(int x, int y, int width, int height, int startAngle, int spanAngle) void QPainter::drawChord(const QRect &rectangle, int startAngle, int spanAngle)
drawChord函数用于在一个矩形框架内绘制半圆形图形,前面4个参数决定矩形框架的尺寸,后面两个参数分别指定起始角度和跨度角度。 绘制半圆示例: void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); QPen pen; pen.setWidth(2); painter.setPen(pen); QRectF rectangle(10.0, 20.0, 80.0, 60.0); int startAngle = 30 * 16; int spanAngle = 120 * 16; painter.drawChord(QRectF(10.0, 20.0, 80.0, 60.0), startAngle, spanAngle); }
图9-3-7 绘制半圆效果 13. 绘制多边形 void QPainter::drawPolygon(const QPointF *points, int pointCount, Qt::FillRule fillRule = Qt::OddEvenFill) void QPainter::drawPolygon(const QPolygonF &points, Qt::FillRule fillRule = Qt::OddEvenFill) void QPainter::drawPolygon(const QPoint *points, int pointCount, Qt::FillRule fillRule = Qt::OddEvenFill) void QPainter::drawPolygon(const QPolygon &points, Qt::FillRule fillRule = Qt::OddEvenFill)
绘制多边形方式原理是使用一个数组指定多个点的位置,然后drawPolygon函数根据数组里指定的位置将所有的点按照顺序连接在一起。 注意:绘制多边形时,在数组内指定点位置的顺序很重要,必须要按照的正常的顺序连接,以绘制六边形为例,点的顺序如下图: 绘制三角形与六边形示例: void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); QPen pen; pen.setWidth(4); painter.setPen(pen); static const QPointF points[] = { QPointF(10.0, 10.0), QPointF(100.0,50.0), QPointF(10.0, 50.0), }; //指定三角形三个点的位置 painter.drawPolygon(points, 3); static const QPointF points_2[] = { QPointF(180.0, 20.0), QPointF(240.0, 40.0), QPointF(240.0, 80.0), QPointF(180.0, 100.0), QPointF(120.0,80.0), QPointF(120.0, 40.0) };//指定六边形6个点的位置 painter.drawPolygon(points_2, 6); }
图9-3-8 绘制多边形效果 14. 绘制凸面多边形 void QPainter::drawConvexPolygon(const QPointF *points, int pointCount) void QPainter::drawConvexPolygon(const QPolygonF &polygon) void QPainter::drawConvexPolygon(const QPoint *points, int pointCount)
绘制三角形示例: void Widget::paintEvent(QPaintEvent *event) { //指定三角形三个顶点的位置 static const QPoint angle[3] = { QPoint(20, 20), QPoint(-20, 20), QPoint(0, -90) }; QPainter painter(this); QPen pen; pen.setWidth(4); painter.setPen(pen); painter.setRenderHint(QPainter::Antialiasing);//绘制的图像反锯齿 painter.setBrush(QColor(255, 0, 255));//设置画刷颜色 painter.translate(width() / 2, height() / 2);//指定窗口的中心位置为当前绘图的原点坐标 painter.drawConvexPolygon(angle, 3);//绘制多边形 } //如果不需要画最外层的黑色边界线,可以进行设置:painter.setPen(Qt::NoPen);
图9-3-9 绘制三角形 15. 填充实心矩形 void QPainter::fillPath(const QPainterPath &path, const QBrush &brush) void QPainter::fillRect(const QRectF &rectangle, const QBrush &brush) void QPainter::fillRect(int x, int y, int width, int height, const QBrush &brush) void QPainter::fillRect(const QRect &rectangle, const QBrush &brush) void QPainter::fillRect(const QRectF &rectangle, const QColor &color) void QPainter::fillRect(int x, int y, int width, int height, const QColor &color) void QPainter::fillRect(const QRect &rectangle, const QColor &color) void QPainter::fillRect(int x, int y, int width, int height, Qt::GlobalColor color) void QPainter::fillRect(const QRect &rectangle, Qt::GlobalColor color) void QPainter::fillRect(const QRectF &rectangle, Qt::GlobalColor color) void QPainter::fillRect(int x, int y, int width, int height, Qt::BrushStyle style) void QPainter::fillRect(const QRect &rectangle, Qt::BrushStyle style) void QPainter::fillRect(const QRectF &rectangle, Qt::BrushStyle style)
FillRect函数用指定的画刷进行填充矩形,参数包括了矩形的左上角位置和矩形的右下角位置。填充的颜色可以使用QBrush(画刷)类指定也可以使用QColor类指定。其中QBrush画刷可以加载指定图片为当前的填充颜色。 示例: void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); QPen pen; pen.setWidth(4); painter.setPen(pen); painter.fillRect(10,10,100,100,QBrush(QPixmap("E:/1.png"))); painter.fillRect(120,10,200,100,QColor(255,0,0)); }
图9-3-9 填充矩形 16. 绘制圆角矩形 void QPainter::drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode = Qt::AbsoluteSize) void QPainter::drawRoundedRect(int x, int y, int w, int h, qreal xRadius, qreal yRadius, Qt::SizeMode mode = Qt::AbsoluteSize) void QPainter::drawRoundedRect(const QRect &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode = Qt::AbsoluteSize)
drawRoundedRect函数绘制的矩形四角为弧形,其中xRadius代表x坐标方向上的半径,yRadius代表y坐标方向上的半径。当Qt::SizeMode模式选择为Qt::RelativeSize模式时,xRadius和yRadius需要按照百分比指定,分别为矩形的宽度和高度的一半,范围在0.0到100.0之间。 绘制圆角矩形示例: void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); QPen pen; pen.setWidth(4); painter.setPen(pen); painter.drawRoundedRect(QRectF(10.0, 20.0, 200.0, 100.0), 40.0, 40.0); }
图9-3-10 绘制圆角矩形 17. 绘制QPainterPath提供的图形路径 void QPainter::drawPath(const QPainterPath &path)
QPainterPath是由一些图形组成的对象。如曲线、矩形、椭圆等。主要的用途是,能保存已经绘制好的图形。实现图形元素的构造和复用;图形状只需创建一次,然后可以调用QPainter::drawPath()函数多次绘制。后面将详细介绍QPainterPath类的使用方方法。 示例: void Widget::paintEvent(QPaintEvent *event) { QPainterPath path; path.cubicTo(80, 10, 50, 50, 80, 80);//绘制曲线 QPainter painter(this); painter.drawPath(path); }
图9-3-10 绘制曲线 18. 绘制图片相关函数 (1) void QPainter::drawImage(const QRectF &target, const QImage &image, const QRectF &source, Qt::ImageConversionFlags flags = Qt::AutoColor) (2) void QPainter::drawImage(const QRect &target, const QImage &image, const QRect &source, Qt::ImageConversionFlags flags = Qt::AutoColor) (3) void QPainter::drawPixmap(const QRectF &target, const QPixmap &pixmap, const QRectF &source) (4) void QPainter::drawPixmap(const QRect &target, const QPixmap &pixmap, const QRect &source) (5) void QPainter::drawPicture(const QPointF &point, const QPicture &picture) (6) void QPainter::drawPicture(const QPoint &point, const QPicture &picture)
drawImage、drawPixmap、drawPicture三个绘图函数用于在指定的矩形框架内绘制图片。如果矩形的尺寸小于或者大于图片本身的源尺寸,绘图函数会按照矩形框架的大小进行绘制图片。 其中target参数用于指定矩形框架的尺寸,source参数用于指定图片的源尺寸。 绘制图片示例: void Widget::paintEvent (QPaintEvent *event) { QImage image("E:/a.png"); QRectF target(10.0, 20.0, 100.0, 100.0); //矩形的尺寸 QRectF source(0.0, 0.0,image.width(),image.height());//图片的源尺寸 QPainter painter(this); painter.drawImage(target, image, source);//绘制图片 }
图9-3-11 绘制图片示例 19. 设置组合模式 void QPainter::setCompositionMode(CompositionMode mode) //设置组合模式 CompositionMode QPainter::compositionMode() const //获取组合模式
组合模式用于将一个指定的像素源与另一个图像的像素合并。 以下示例代码通过CompositionMode函数将两张图片合成一张图片。 QImage baseImage("E:/a.png"),overlayImage("E:/1.png"); QImage imageWithOverlay = QImage(baseImage.size(), QImage::Format_ARGB32_Premultiplied); QPainter painter(&imageWithOverlay); painter.setCompositionMode(QPainter::CompositionMode_Source); //设置模式 painter.fillRect(imageWithOverlay.rect(), Qt::transparent); painter.drawImage(0, 0, baseImage); painter.drawImage(0, 0, overlayImage); painter.end(); imageWithOverlay.save("E:/image.png");//保存图片
图9-3-12 合成图片示例 20. 擦除指定矩形区域 void QPainter::eraseRect(const QRectF &rectangle) void QPainter::eraseRect(int x, int y, int width, int height) void QPainter::eraseRect(const QRect &rectangle)
eraseRect函数使用当前的背景刷,擦除指定的矩形范围。相当于调用了以下代码: QPainter painter(this); painter.fillRect(0,0,50,50, painter.background()); //使用背景色填充指定矩形区域 等价于: painter.eraseRect(0,0,50,50); //擦除指定区域
21. 设置背景模式 void QPainter::setBackgroundMode(Qt::BGMode mode) //设置模式 Qt::BGMode QPainter::backgroundMode() const //获取当前模式
Qt::BGMode描述的背景模式分为透明模式Qt::TransparentMode和不透明模式Qt::OpaqueMode。 22. 设置画刷 void QPainter::setBrush(const QBrush &brush) //设置画刷QBrush void QPainter::setBrush(Qt::BrushStyle style) //设置画刷样式 const QBrush &QPainter::brush() const
画刷样式枚举值(Qt::BrushStyle)如下: 图9-3-13 画刷样式 23. 设置背景画刷 void QPainter::setBackground(const QBrush &brush) const QBrush &QPainter::background() const
示例: QPainter painter(this); painter.setBackground(QBrush(Qt::red)); //设置背景刷 painter.eraseRect(0,0,50,50); //擦除指定区域
24. 设置画刷的原点位置 void QPainter::setBrushOrigin(const QPointF &position) void QPainter::setBrushOrigin(const QPoint &position) void QPainter::setBrushOrigin(int x, int y)
25. 设置抗锯齿属性 void QPainter::setRenderHint(RenderHint hint, bool on = true)
抗锯齿(反走样)是图形学中的重要概念,用以防止“锯齿”现象出现。很多系统的绘图API里面都会内置抗锯齿的算法,不过默认一般都是关闭的,需要手动开启。 启用抗锯齿示例: void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); QPen pen; pen.setWidth(4); painter.setPen(pen); painter.drawRoundedRect(QRectF(10.0, 20.0, 100.0, 100.0), 40.0, 40.0); painter.setRenderHint(QPainter::Antialiasing,true);//启用抗锯齿 painter.drawRoundedRect(QRectF(120.0, 20.0, 100.0, 100.0), 40.0, 40.0); }
图9-3-14 抗锯齿效果 开启抗锯齿功能后和没开之前画的图形差别是很大的,明显可以看出线变得很平滑。 26. 坐标系统转换相关函数 void QPainter::translate(const QPointF &offset) void QPainter::translate(const QPoint &offset) void QPainter::translate(qreal dx, qreal dy) 坐标系统平移变换。改变坐标系统的原点位置。 例如: painter.translate(100,100); //将点(100,100)设为原点 void QPainter::rotate(qreal angle) 坐标系统顺时针旋转。单位为角度 void QPainter::shear(qreal sh, qreal sv) 坐标系统扭曲变换 void QPainter::scale(qreal sx, qreal sy) 坐标系统的缩放 void QPainter::restore() 恢复坐标系统的状态 void QPainter::save() 保存坐标系统的状态
9.3.2 QPainter坐标系统转换示例 1. 使用translate函数实现坐标平移变换 下面代码使用translate函数分别指定了不同的坐标位置作为当前绘图的原点坐标,并绘制了一个矩形和一个圆。观察矩形和圆绘制的位置即可明白translate函数用途。 void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); QPen pen; //创建一个默认的画笔 pen.setStyle(Qt::SolidLine);//设置样式 pen.setWidth(5); //设置宽度 pen.setBrush(Qt::red);//设置画刷 painter.setPen(pen); painter.translate(100,100); //将(100,100)设为原点 painter.drawRect(0,0,50,50);//绘制矩形 painter.translate(-100,-100);//将坐标系统还原到(0,0) painter.drawEllipse(10,10,50,50); //绘制圆; }
图9-3-14 坐标平移转换效果 2. 使用rotate函数实现坐标系统顺时针旋转 默认情况下rotate()函数是以原点为中心进行顺时针旋转的,如果我们想要使其以其他点为中心进行旋转,就需要使用translate进行原点坐标的变换。 1) 下面代码先通过translate函数指定坐标系统的原点坐标,再通过rotate函数顺时针旋转坐标系统,旋转一次坐标系统就绘制一条线,观察线的位置理解rotate函数的用法。 void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); QPen pen; //创建一个默认的画笔 pen.setStyle(Qt::SolidLine);//设置样式 pen.setWidth(5); //设置宽度 pen.setBrush(Qt::red); //设置画刷 painter.setPen(pen); painter.translate(100,10); //指定绘图系统的原点坐标 painter.drawLine(0,0,100,0);//绘制线 painter.rotate(30); //以原点为中心,顺时针旋转30度 painter.drawLine(0,0,100,0); painter.rotate(30); painter.drawLine(0,0,100,0); painter.rotate(30); painter.drawLine(0,0,100,0); painter.rotate(30); painter.drawLine(0,0,100,0); }
图9-3-15 坐标旋转 2) translate函数实现图片旋转示例 void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); QPixmap pix; pix.load("E:/1.png"); painter.translate(50,50); //让图片的中心作为旋转的中心 painter.rotate(90); //顺时针旋转90度 painter.translate(-50,-50); //使原点复原 painter.drawPixmap(0,0,100,100,pix);//绘制图片 }
图9-3-16 实现图片旋转 3. shear函数实现坐标系统扭曲变换 shear函数原型:void QPainter::shear(qreal sh, qreal sv) 其中qreal sh参数指定横向扭曲,0表示不扭曲。qreal sv参数指定纵向扭曲,0表示不扭曲。 下面代码使用shear函数实现图片横向和纵向扭曲效果。 void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); QPixmap pix; pix.load("E:/1. jpg"); painter.drawPixmap(0,0,100,100,pix); painter.shear(0.5,0); //横向扭曲 painter.drawPixmap(100,0,100,100,pix); }
图9-3-17 图片扭曲效果 4. 使用scale函数实现实现坐标缩放 下面代码使用scale函数实现图片的放大。注意:Scale函数是将坐标系统进行缩放。 void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); QPixmap pix; pix.load("E:/1.jpg"); painter.drawPixmap(0,0,pix); painter.scale(2,2); //水平和垂直方向坐标系统各放大2倍 painter.drawPixmap(100,0,pix); }
图9-3-18 坐标系统放大小效果 5. 保存状态和恢复坐标状态 save函数用于保存当前坐标系统的状态,restore函数用于恢复之前保存的坐标系统状态。合理的运用这两个函数可以方便的绘制出各种形状的图形。 void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); QPixmap pix; pix.load("E:/1.jpg"); painter.save(); //保存坐标系状态 painter.translate(100,100); //将(100,100)设为原点 painter.drawPixmap(0,0,100,100,pix); painter.restore(); //恢复以前的坐标系状态 painter.drawPixmap(0,0,100,100,pix); }
图9-3-19 坐标状态的保存和恢复效果9.3.3 QPainter绘制模拟时钟实例 本实例通过QPainter类绘制了一个模拟时钟,实现时钟与系统时间同步显示。通过本实例可以学习上面介绍QPainter类相关的函数组合用法。(配套程序编号CH9-1) 1. “widget.h”文件代码 “widget.h”文件中重载了paintEvent事件函数。 #ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QWidget> #include <QPainter> #include <QTime> #include <QTimer> class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = 0); ~Widget(); private: void paintEvent(QPaintEvent *event); //声明paintEvent函数 }; #endif // WIDGET_H
2. “widget.cpp”文件代码 “widget.cpp”文件实现了paintEvent函数,在函数paintEvent中编写了时钟的绘制代码。Widget窗口构造函数中创建了定时器,设置定时器的超时时间为1秒钟;并将定时器的超时时间与update()槽函数关联在一起。每当调用一次update函数就会产生一次重绘事件,就会执行一次paintEvent函数。因为定时器的超时时间为1秒,所以就每秒在paintEvent函数里重绘一次时钟,实现了模拟时钟的效果。 #include "widget.h" Widget::Widget(QWidget *parent) : QWidget(parent) { QTimer *timer = new QTimer(this); timer->start(1000);//定时器定时1秒钟 //将定时器超时信号与窗口更新槽函数关联在一起。 connect(timer,SIGNAL(timeout()),this,SLOT(update())); } Widget::~Widget() { } void Widget::paintEvent(QPaintEvent *event) { /*1. 定义三个时针的坐标位置*/ //定义绘制时针的4个顶点坐标. 绘制多边形 static const QPoint HourHand[4] = { {3, 8}, {0, 16}, {-3, 8}, {0, -40} }; //定义绘制分针的4个顶点坐标 static const QPoint MinuteHand[4] = { {3, 8}, {0, 16}, {-3, 8}, {0, -70} }; //定义绘制秒针的3个顶点坐标 static const QPoint SecondHand[3] = { {3, 8}, {-3, 8}, {0, -90} }; /*2. 定义填充表针的画刷颜色*/ QColor HourColor(70, 88, 255,255); //时针颜色,最后一个参数表示透明度 QColor MinuteColor(0, 127, 127, 200);//分针颜色 QColor SecondColor(255, 0, 0, 150); //秒针颜色 QColor FrameColor(127, 127, 0, 150); //外框颜色 /*3. 设置QPainter绘制参数*/ int side =width()<height()?width():height();//得到窗体宽、高中的最小值,用于设置绘制的范围 QTime time = QTime::currentTime();//获取当前的系统时间 QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing);//启用反锯齿 painter.translate(width() / 2, height() / 2);//将坐标原点定义到窗体的中央位置 painter.scale(side / 200.0, side / 200.0);//设置坐标系统缩放大小。让时针根据窗体改变显示的大小。 /*4. 绘制外框*/ painter.setPen(FrameColor); painter.drawEllipse(-96,-96,96*2,96*2); //绘制外框 /*5. 绘制时针*/ painter.setPen(Qt::NoPen); //设置画笔不使用边线。相当于画笔是透明状态 painter.setBrush(HourColor);//设置画刷颜色 painter.save();//保存当前坐标系统状态 //将painter(的”视角“)根据时间参数转移(30° * (小时 + 分钟 / 60)) painter.rotate(30.0 * ((time.hour() + time.minute() / 60.0))); painter.drawConvexPolygon(HourHand, 4);//绘制时针 painter.restore();//恢复坐标系统状态,方便绘制下一个图形 /*6. 绘制大刻度*/ painter.setPen(HourColor); //设置画笔颜色 for (int i = 0; i < 12; ++i) //绘制十二个大刻度 { painter.drawLine(88, 0, 96, 0);//绘制刻度。刻度的长度为(96-88) painter.rotate(30.0);//顺时针旋转30度 } /*5. 绘制分针、秒针、小刻度*/ painter.setPen(Qt::NoPen); //填充分针,不需要边线所以NoPen painter.setBrush(MinuteColor); //设置画刷颜色 painter.save(); //保存坐标系统 painter.rotate(6.0 * (time.minute() + time.second() / 60.0));//设旋转(角度 = 6° * (分钟 + 秒 / 60)) painter.drawConvexPolygon(MinuteHand, 4);//填充分针部分 painter.restore(); //恢复保存前坐标系统状态 painter.setPen(MinuteColor); //设置画刷颜色 for (int j = 0; j < 60; ++j) //循环60次,绘制表盘。 { if ((j % 5) != 0)//判断是否能被5整除(能被5整除表示是正点刻度) { painter.drawLine(92, 0, 96, 0);//不是正点刻度,绘制长4个像素的直线 } painter.rotate(6.0);//旋转六度 }//循环60次,每次旋转6度 painter.setPen(Qt::NoPen); //填充分针时不需要边线。 painter.setBrush(SecondColor);//设置画刷颜色 painter.save(); //保存坐标系统 painter.rotate(6.0 * time.second());//设置旋转(6° * 秒) painter.drawConvexPolygon(SecondHand, 3);//绘制秒针 painter.restore();//恢复保存前坐标系统状态 } //注意:每次需要改变坐标系统时,就要先保存坐标系统状态,防止破坏之前的坐标位置。
3. 时钟运行效果 图9-3-20 模拟时钟运行效果图9.4 QPainterPath图形容器介绍 QPainterPath类提供了一个容器,用于绘图操作,可以创建和重用绘制的图形形状。它是由一些图形如曲线、矩形、椭圆组成的对象。主要的用途是:能保存已经绘制好的图形,实现图形元素的构造和复用。图形状只需创建一次,然后可调用QPainter::drawPath()函数进行多次绘制。painterpath可以加入闭合或者不闭合的图形。例如:矩形、椭圆和曲线等。9.4.1 QPainterPath类相关函数介绍 1. 指定绘图的坐标位置 void QPainterPath::moveTo(const QPointF &point) void QPainterPath::moveTo(qreal x, qreal y)
moveTo函数可以将当前的绘图原点移动到指定位置。 绘制线示例: void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); QPainterPath path; path.moveTo(QPointF(20,20)); //指定绘图原点位置 path.lineTo(200,20); //指定线段的终点 painter.drawPath(path); //绘制包含的路径 }
图9-4-1 绘制线 2. 添加椭圆绘制方法 void QPainterPath::addEllipse(const QRectF &boundingRectangle) void QPainterPath::addEllipse(qreal x, qreal y, qreal width, qreal height) void QPainterPath::addEllipse(const QPointF ¢er, qreal rx, qreal ry)
示例: void Widget::paintEvent(QPaintEvent *event) { QRectF boundingRectangle(10,10,150,100); QPainterPath myPath; myPath.addEllipse(boundingRectangle); QPainter painter(this); painter.setBrush(Qt::red); painter.setPen(Qt::blue); painter.drawPath(myPath); }
图9-4-2 绘制椭圆 3. 添加多边形绘制方法 void QPainterPath::addPolygon(const QPolygonF &polygon)
注意:如果需要将多边形最开始一个点与最后一点连接在一起绘制一条线,可以使用closeSubpath()函数实现。 示例: void Widget::paintEvent(QPaintEvent *event) { QPainterPath myPath; QPolygonF myPolygon; myPolygon<<QPointF(50.0, 0.0)<<QPointF(0.0,100.0)<<QPointF(100.0, 100.0); myPath.addPolygon(myPolygon); QPainter painter(this); painter.setBrush(Qt::red); painter.setPen(Qt::blue); painter.drawPath(myPath); }
图9-4-3 绘制三角形 4. 添加矩形绘制方法 void QPainterPath::addRect(const QRectF &rectangle) void QPainterPath::addRect(qreal x, qreal y, qreal width, qreal height)
示例: void Widget::paintEvent(QPaintEvent *event) { QPainterPath myPath; myPath.addRect(10,10,100,100); QPainter painter(this); painter.setBrush(Qt::red); painter.setPen(Qt::blue); painter.drawPath(myPath); }
5. 添加文本绘制方法 void QPainterPath::addText(const QPointF &point, const QFont &font, const QString &text)
const QPointF &poin填入的x,y坐标位置是文本显示的基线位置。(x,y)基线位置如下图所示: 示例: void Widget::paintEvent(QPaintEvent *event) { QPen myPen; QFont myFont("黑体",80); QPointF baseline(100,100); QPainterPath myPath; myPath.addText(baseline, myFont, tr("Qt")); QPainter painter(this); painter.setBrush(Qt::blue); painter.setPen(myPen); painter.drawPath(myPath); }
图9-4-4 绘制文本 6. 绘制弧形 void QPainterPath::arcTo(const QRectF &rectangle, qreal startAngle, qreal sweepLength)
公告
可以关注我们的微信公众号yafeilinux_friends获取最新动态,或者加入QQ会员群进行交流:190741849、186601429(已满)
我知道了