图形绘制 QPainter

QPainter painter(this); // 会立即开始在设备上绘制,自动调用begin()函数,然后析构函数中调用end()函数结束绘制。
QPainter painter;// 不带参数时,可以在后面调用QPainter::begin(QPaintDevice *device)来指定绘制设置,然后用完再调用end()函数。

void Widget::paintEvent((QPaintEvent *event)  
{  
        QPainter painter(this); //this为绘图设备,即表明在该部件上进行绘制  
        painter.drawLine(QPaint(0, 0), QPaint(100, 100));  
}  
//等价于
void Widget::paintEvent((QPaintEvent *event)  
{  
        QPainter painter;  
        painter.begin(this);  
        painter.drawLine(QPaint(0, 0), QPaint(100, 100));  
        painter.end();  
}  

使用画刷

画刷可以设置颜色和填充模式

QBrush brush(QColor(0,0,255), Qt::Dense4Pattern);  
painter.setBrush(brush);  

使用画笔

//参数为:画刷,线宽,画笔风格,画笔端点,画笔连接风格  
QPen pen(Qt::green, 5, Qt::DotLine, Qt::RoundCap, Qt::RoundJoin);  
painter.setPen(pen);  

QPainter 常用的画图方法,都是以 draw 开头,非常直观的列出了绘图函数和绘制出来的图形:
这里写图片描述

坐标系

数学中使用的坐标系是笛卡尔坐标系,X 轴正向向右,Y 轴正向向上。但是,QPainter 也有自己的坐标系,和笛卡尔坐标系有点不一样,原点在 widget 的左上角而不是正中心,X 轴正向向右,Y 轴正向向下。注意: 每个 widget 都有自己独立的坐标系。
这里写图片描述

QPainter是一个状态机

所谓状态机,就是说,QPainter保存的只是各种状态。怎么理解呢?比如,你把颜色设置成红色,那么,直到你重新设置另外的颜色,它的颜色会一直是红色。它的状态不会自己恢复,除非你使用了各种set函数。因此,如果在上面的代码中,我们在椭圆绘制之后再画一个椭圆,它的样式还会是绿色5px的轮廓和蓝色的填充,除非你显式地调用了set进行更新。这可能是绘图系统较多的实现方式,因为无论是OpenGL、QPainter还是Java2D,都是这样实现的。

画线 - drawLine()

void MainWidget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    painter.drawLine(30, 30, 150, 150);
}

画多线段 - drawLines()

给定 N 个点,第 1 和第 2 个点连成线,第 3 和第 4 个点连成线,……,N 个点练成 (N+1)/2 条线,如果 N 是奇数,第 N 个点和 (0,0) 连成线。

void MultipleLinesWidget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.translate(20, 20);
    static const QPointF points[4] = {
        QPointF(0.0, 100.0),
        QPointF(20.0, 0.0),
        QPointF(100.0, 0.0),
        QPointF(120.0, 100.0)
    };
    painter.drawLines(points, 2); // 4 个点连成 2 条线
}

画折线- drawPolyline()

给定 N 个点,第 1 和第 2 个点连成线,第 2 和第 3 个点连成线,……,第 N-1 和第 N 个点连成线,N 个点共连成 N-1 条线。

void PolylineWidget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.translate(20, 20);
    static const QPointF points[4] = {
        QPointF(0.0, 100.0),
        QPointF(20.0, 0.0),
        QPointF(100.0, 0.0),
        QPointF(120.0, 100.0)
    };
    painter.drawPolyline(points, 4);
}

画多边形 - drawPolygon()

给定 N 个点,第 1 和第 2 个点连成线,第 2 和第 3 个点连成线,……,第 N-1 和第 N 个点连成线,第 N 个点和第 1 个点连接成线形成一个封闭的多边形。
在我们学习OpenGL的时候,肯定听过这么一句话:OpenGL是一个状态机。所谓状态机,就是说,OpenGL保存的只是各种状态。怎么理解呢?比如,你把颜色设置成红色,那么,直到你重新设置另外的颜色,它的颜色会一直是红色。QPainter也是这样,它的状态不会自己恢复,除非你使用了各种set函数。因此,如果在上面的代码中,我们在椭圆绘制之后再画一个椭圆,它的样式还会是绿色5px的轮廓和蓝色的填充,除非你显式地调用了set进行更新。这可能是绘图系统较多的实现方式,因为无论是OpenGL、QPainter还是Java2D,都是这样实现的

drawPolygon() 和 drawPolyline() 很像,但是 drawPolygon() 画的是一个封闭的区域,可以填充颜色,而 drawPolyline() 画的是一些线段,即使它们连成一个封闭的区域也不能填充颜色。

void PolygonWidget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.translate(20, 20);
    static const QPointF points[4] = {
        QPointF(0.0, 100.0),
        QPointF(20.0, 0.0),
        QPointF(100.0, 0.0),
        QPointF(120.0, 100.0)
    };
    painter.setBrush(Qt::yellow);
    painter.drawPolygon(points, 4);
}

可以用 drawPolygon() 来画圆,其实本没有圆,正多边形的边多了,便成了圆,这正是计算机里绘制曲线的原理,插值逼近,在曲线上取 N 个点,点之间用线段连接起来,当 N 越大时,连接出来的图形就越平滑,越接近曲线。

void PolygonCircleWidget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing); // 启用抗锯齿效果
    painter.translate(width() / 2, height() / 2); // 把坐标原点移动到 widget 的中心
    painter.setBrush(Qt::lightGray);
    const int COUNT  = 10;  // 边数,越大就越像圆
    const int RADIUS = 100; // 圆的半径
    QPointF points[COUNT];  // 顶点数组
    for (int i = 0; i < COUNT; ++i) {
        float radians = 2 * M_PI / COUNT * i; // M_PI 是 QtMath 里定义的,就是 PI
        float x = RADIUS * qCos(radians);
        float y = RADIUS * qSin(radians);
        points[i] = QPointF(x, y);
    }
    painter.drawPolygon(points, COUNT);
}

画矩形 - drawRect()

void MainWidget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.translate(30, 30);
    int x = 0;
    int y = 0;
    int w = 100;
    int h = 100;
    painter.drawRect(x, y, w, h);
}

画圆角矩形- drawRoundRect() & drawRoundedRect()

绘制圆角矩形有 2 个方法:drawRoundRect() 和 drawRoundedRect(),需要给定圆角矩形左上角的坐标、长、宽、圆角的半径。

当 drawRoundedRect() 中第 7 个参数 Qt::SizeMode 为 Qt::RelativeSize 时,表示圆角半径的单位是百分比,取值范围是 [0, 100],此时 drawRoundedRect() 等价于 drawRoundRect(),其实底层是用这个百分比和对应边长的一半相乘得到圆角的半径(单位是像素)。Qt::SizeMode 为 Qt::AbsoluteSize 时,表示圆角半径的单位是像素。

void RoundRectWidget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setBrush(Qt::lightGray);
    painter.translate(30, 30);
    painter.drawRoundRect(0, 0, 100, 100, 50, 50); // 50%, 50%
    painter.drawRoundedRect(130, 0, 100, 100, 50, 50, Qt::AbsoluteSize); // 50px, 50px
    painter.drawRoundedRect(260, 0, 100, 100, 100, 100, Qt::RelativeSize); // 100%, 100%
}

画圆、椭圆 - drawEllipse()

void EllipseWidget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.translate(30, 30);
    painter.drawRect(0, 0, 200, 100);    // 椭圆的包围矩形
    painter.setBrush(Qt::lightGray);
    painter.drawEllipse(0, 0, 200, 100); // 椭圆
    painter.drawEllipse(230, 0, 100, 100); // 圆
}

画弧、弦、饼图 - drawArc()、drawChord()、drawPie()

画弧使用 drawArc()
画弦使用 drawChord()
画饼图用 drawPie()

void QPainter::drawArc(const QRectF & rectangle, int startAngle, int spanAngle)
void QPainter::drawPie(const QRectF & rectangle, int startAngle, int spanAngle)
void QPainter::drawChord(const QRectF & rectangle, int startAngle, int spanAngle)

这里写图片描述
rectangle: 包围矩形
startAngle: 开始的角度,单位是十六分之一度,如果要从 45 度开始画,则 startAngle 为 45 * 16
spanAngle: 覆盖的角度,单位是十六分之一度
绘制圆心为包围矩形的正中心,0 度在圆心的 X 轴正方向上
角度的正方向为逆时针方向
这里写图片描述

void ArcChordPieWidget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    static int startAngle = 45 * 16; // 开始角度是 45 度
    static int spanAngle = 130 * 16; // 覆盖角度为 130 度
    static QRectF boundingRect(0, 0, 150, 150); // 包围矩形
    painter.translate(30, 30);
    painter.setBrush(Qt::NoBrush);
    painter.drawRect(boundingRect); // 绘制包围矩形
    painter.setBrush(Qt::lightGray);
    painter.drawArc(boundingRect, startAngle, spanAngle); // 画弧
    painter.translate(180, 0);
    painter.setBrush(Qt::NoBrush);
    painter.drawRect(boundingRect); // 绘制包围矩形
    painter.setBrush(Qt::lightGray);
    painter.drawChord(boundingRect, startAngle, spanAngle); // 画弦
    painter.translate(180, 0);
    painter.setBrush(Qt::NoBrush);
    painter.drawRect(boundingRect); // 绘制包围矩形
    painter.setBrush(Qt::lightGray);
    painter.drawPie(boundingRect, startAngle, spanAngle); // 画饼图
}

绘制 QPixmap - drawPixmap()

void MainWidget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    QPixmap pixmap(":/img/Butterfly.png"); // 从资源文件读取 pixmap

    painter.drawPixmap(0, 0, pixmap); // 绘制 pixmap
}

绘制 QImage - drawImage()

void MainWidget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    QImage image(":/img/Butterfly.png"); // 从资源文件读取 image
    painter.drawImage(0, 0, image); // 绘制 image
}

绘制路径QPainterPath - drawPath()

    QPainterPath path;  
    path.addEllipse(-4, -4, 8, 8);//添加一个圆  
    path.addRect(-5, -5, 10, 10); //添加一个矩形  
    painter.drawPath(path);  

填充与擦除

/使用画刷填充一个矩形区域  
painter.fillRect(QRect(10,100,150,20), QBrush(Qt::darkYellow));  

//擦除一个矩形区域的内容  
painter.eraserRect(QRect(50,0,50,120)); 
  • 8
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值