找回密码
 立即注册
Qt开源社区 门户 查看内容

QT软件开发-第九章 图形绘制与视图框架:9.3~9.5

2019-4-24 11:49| 发布者: admin| 查看: 3720| 评论: 0

摘要: 点击上方蓝字关注我们9.3 QPainter图形绘制Qt绘图主要用到QPainter类,QPainter类提供了许多高度优化的函数去做大部分的GUI绘制工作。它可以画简单的线到复杂的形状,通常情况下,QPainter是在widget的painter绘图事 ...


点击上方蓝字关注我们




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(已满) 我知道了