2.绘图

Qt提供了画图相关的APL,可以允许我们在窗口上绘制任意的图形形状,来完成更复杂的界面设计

所谓的"控件",本质上也是通过画图的方式画上去的

画图AP|和控件之间的关系,可以类比成机器指令和高级语言之间的关系

控件是对画图API的进一步封装;画图API是控件的底层实现

说明

QPainter

"绘画者"或者"画家"

用来绘图的对象,提供了一系列drawXXX方法,可以允许我们绘制各种图形

QPaintDevice

"画板”

描述了QPainter把图形画到哪个对象上.像咱们之前用过的QWidget也是一种QPaintDevice(QWidgetQPaintDevice的子类)

QPen

"画笔"

描述了QPainter画出来的线是什么样的

QBrush

"画刷"

描述了QPainter填充一个区域是什么样的.

绘图API的使用,一般不会在QWidget的构造函数中使用,而是要放到paintEvent事件中

关于paintEvent

paintEvent会在以下情况下被触发:

  • 控件首次创建
  • 控件被遮挡,再解除遮挡
  • 窗口最小化,再恢复
  • 控件大小发生变化时
  • 主动调用repaint()或者update()方法。(这两个方法都是QWidget的方法)

因此,如果把绘图 API 放到构造函数中调用,那么一旦出现上述的情况,界面的绘制效果就无法确保符合预期了

①绘制各种形状

1>绘制线段

 

078eb3b06bc2380568b82ecba3581d0f.png

 

0e3ddd792bb6e147f75ac3845da7ebd7.png

①:void drawLine(const QPoint &p1,const QPoint &p2); p1:绘制起点坐标;p2:绘制终点坐标

②:void QPainter:drawRect(int x,int y,int width,int height); x:窗口横坐标;y:窗口纵坐标;width:所绘制矩形的宽度;height:所绘制矩形的高度;

2>绘制矩形

 

bddce80bf464dd5d17ed3a600adc5895.png

void QPainter:drawRect(int x,int y,int width,int height); ×:窗口横坐标;y:窗口纵坐标;width:所绘制矩形的宽度;height:所绘制矩形的高度;

3>绘制圆形

 

df6ea151bf079d60baae622f85c2cb4e.png

void QPainter:drawEllipse(const QPoint &center,int rx,int ry); center:中心点坐标; r×:横坐标; ry:纵坐标

4>绘制文本

 

e69f0d2db878d5e2dad54ab03aa05260.png

#include "widget.h"
#include "ui_widget.h"
#include<QPainter>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::paintEvent(QPaintEvent *)
{
    //实例化画家对象,this表示的是在当前窗口中绘画,即绘图设备
    QPainter painter(this);

    //画一条线
    painter.drawLine(QPoint(20,20),QPoint(200,20));

    //再画一条线
    painter.drawLine(20,100,200,100);

    //绘制矩形
    painter.drawRect(120,120,100,50);

    //绘制圆
    painter.drawEllipse(QPoint(400,200),50,50);



    //绘制文本
    QFont font("华文行楷",24);
    painter.setFont(font);

    //设置画笔颜色
    painter.setPen(Qt::blue);

    //画文字
    painter.drawText(QRect(100,200,600,150),"Outlier9");
    //坐标如果写成(0,0),就不会显示出来,因为在基线的位置之上
    //所以一般y设置为100,基线的位置一般大概在文字的三分之二处
}

5>设置画笔

QPainter在绘制时,是有一个默认的画笔的。在使用时也可以自定义画笔。在Qt中,QPen类中定义了QPainter应该如何绘制形状、线条和轮廓。同时通过QPen类可以设置画笔的线宽、颜色、样式、画刷等。

画笔的颜色可以在实例化画笔对象时进行设置

画笔的宽度是通过setWidth()方法进行设置

画笔的风格是通过setStyle()方法进行设置

设置画刷主要是通过setBrush()方法

  • 设置画笔颜色:QPen:QPen(const QColor &color) 画笔的颜色主要是通过QColor类设置;
  • 设置画笔宽度:void QPen:setWidth(int width)
  • 设置画笔风格:void QPen:setStyle(Qt:PenStyle style)

画笔风格展示:

 

9bb66c4b77a9a2477682c2068f54e588.png

画笔使用

 

1c1e133003b8af4a306b4d2b49d7b632.png

#include "widget.h"
#include "ui_widget.h"
#include<QPainter>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::paintEvent(QPaintEvent *)
{
    //实例化画家对象,this表示的是在当前窗口中绘画,即绘图设备
    QPainter painter(this);


    //设置画笔
    QPen pen(QColor(255,0,0));
    //设置画笔宽度
    pen.setWidth(3);
    //设置画笔风格
    pen.setStyle(Qt::DashLine);
    //设置让画家使用画笔
    painter.setPen(pen);


    //画一条线
    painter.drawLine(QPoint(20,20),QPoint(200,20));

    //再画一条线
    painter.drawLine(20,100,200,100);

    //绘制矩形
    painter.drawRect(120,120,100,50);

    //绘制圆
    painter.drawEllipse(QPoint(400,200),50,50);



    //绘制文本
    QFont font("华文行楷",24);
    painter.setFont(font);

    //设置画笔颜色
    painter.setPen(Qt::blue);

    //画文字
    painter.drawText(QRect(100,200,600,150),"Outlier9");
}

6>设置画刷

在Qt中,画刷是使用QBrush类来描述,画刷大多用于填充。QBrush定义了QPainter的填充模式,具有样式、颜色、渐变以及纹理等属性。

画刷的格式中定义了填充的样式,使用Qt:BrushStyle枚举,默认值是Qt:NoBrush,也就是不进行任何填充。可以通过Qt助手查找画刷的格式。如下图示:

 

14195f9db38026f4545bb1fdafc7fd8e.png

 

720c8cdbbb70447ca3d850afe742c397.png

 

0c0e2ad948d760c3584be31b404b4e25.png

 

53c9cf9a9dfbb2d2a17bb188d5477588.png

设置画刷主要通过void QPen:setBrush(const QBrush &brush)方法,其参数为画刷的格式。

 

fda9e6b21086acee8255439bae57ef5b.png

#include "widget.h"
#include "ui_widget.h"
#include<QPainter>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::paintEvent(QPaintEvent *)
{
    //实例化画家对象,this表示的是在当前窗口中绘画,即绘图设备
    QPainter painter(this);


    //设置画笔
    QPen pen(QColor(255,0,0));
    //设置画笔宽度
    pen.setWidth(3);
    //设置画笔风格
    pen.setStyle(Qt::DashLine);
    //设置让画家使用画笔
    painter.setPen(pen);


    //设置画刷,给封闭图形填充颜色
    QBrush brush(Qt::cyan);
    //设置画刷风格
    brush.setStyle(Qt::Dense1Pattern);
    //让画家使用画刷
    painter.setBrush(brush);



    //画一条线
    painter.drawLine(QPoint(20,20),QPoint(200,20));

    //再画一条线
    painter.drawLine(20,100,200,100);

    //绘制矩形
    painter.drawRect(120,120,100,50);

    //绘制圆
    painter.drawEllipse(QPoint(400,200),50,50);



    //绘制文本
    QFont font("华文行楷",24);
    painter.setFont(font);

    //设置画笔颜色
    painter.setPen(Qt::blue);

    //画文字
    painter.drawText(QRect(100,200,600,150),"Outlier9");
}

②绘制图片

Qt提供了四个类来处理图像数据:QImageQPixmapQBitmapQPicture,它们都是常用的绘图设备。其中QImage主要用来进行I/O处理,它对I/O处理操作进行了优化,而且可以用来直接访问和操作像素;QPixmap主要用来在屏幕上显示图像,它对在屏幕上显示图像进行了优化;QBitmapQPixmap的子类,用来处理颜色深度为l的图像,即只能显示黑白两种颜色;QPicture用来记录并重演QPainter命令。这里只讲解QPixmap

 

c4779aa7a2101cd7bc74d6a3c40b7c66.png

添加资源文件时,先将准备好的照片都放到一个文件夹内,文件夹与项目文件同级

 

696d6ccbcad40ca99cbc8e59256242be.png

添加的时候,选中项目文件然后右键add New

 

7452d826f073d6c68c363ed54e84ab30.png

然后把图片都添加进去

 

a756d197231c9d87fde0c263577b11a7.png

点击构建并运行,加载资源图片到项目中

图片的平移、放大缩小、旋转

  • QPainter类中提供了translate()函数来实现坐标原点的改变
  • 图片的放大和缩小可以使用QPainter类中的drawPixmap()函数来实现。
  • 图片的旋转使用的是QPainter类中的rotate()函数,它默认是以原点为中心进行旋转的。如果要改变旋转的中心,可以使用translate()函数完成。

 

069cf57efaabb730102eeb61f78cefdd.png

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

    //声明绘画事件
    void paintEvent(QPaintEvent *event);

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

在绘制图形的过程中,可以通过save()函数来保存画家的状态,使用restore()函数还原画家状态。

save()函数原型

 

99cb039d173c5366fc1640034f6307a5.png

restore()函数原型

 

afe02e78c14ed674bc4cec145845fac5.png

③特殊的绘图设备

  • QPixmap用于在显示器上显示图片
  • QImage用于对图片进行像素级修改
  • QPicture用于对QPainter的一系列操作进行存档

1>QPixmap

QPixmap核心特性:

  • 使用QPainter直接在上面进行绘制图形.
  • 通过文件路径加载并显示图片,
  • 搭配QPainterdrawPixmap()函数,可以把这个图片绘制到一个QLabelQPushButton等控件上
  • 和系统/显示设备强相关,不同系统/显示设备下,QPixmap的显示可能会有所差别

 

9c7f58daa99a9aed46cac2fab323feb2.png

#include "widget.h"
#include "ui_widget.h"
#include<QPixmap>
#include<QPainter>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //Pixmap绘图设备,绘图设备尺寸为500*500
    QPixmap pix(500,500);
    //实例化画家对象
    QPainter painter(&pix);
    //设置画笔颜色
    painter.setPen(Qt::red);
    //画图
    painter.drawEllipse(QPoint(100,100),100,100);
    //保存绘制的图片
    pix.save("D:\\C C++\\program\\QT\\QPainter\\picture\\pix.png");
}

Widget::~Widget()
{
    delete ui;
}

2>QImage

QImage的核心特性:

  • 使用OPainter直接在上面进行绘制图形
  • 通过文件路径加载并显示图片
  • 能够针对图片进行像素级别的操作(操作某个指定的像素).
  • 独立于硬件的绘制系统,能够在不同系统之上提供一致的显示

 

75965c4166e215c27845d0afb5b446bb.png

#include "widget.h"
#include "ui_widget.h"
#include<QPainter>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //绘图设备的大小为500*500,绘图格式为QImage::Format_RGB32
    //绘图格式可通过Qt助手查看
    QImage img(500,500,QImage::Format_RGB32);

    img.fill(Qt::white); // 填充色为白色,默认背景色为黑色

    QPainter painter(&img); //声明画家,画图设备为img

    painter.setPen(QPen(Qt::cyan));//设置画笔颜色为蓝绿色

    painter.drawEllipse(QPoint(200,200),100,100); //画圆
    //保存图片
    img.save("D:\\C C++\\program\\QT\\QImage\\img.jpg");

}

Widget::~Widget()
{
    delete ui;
}

QImage对像素的修改

 

f252eb6b6fd4b90fadcced6bb9bd0ed2.png

#include "widget.h"
#include "ui_widget.h"
#include<QPainter>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::paintEvent(QPaintEvent *)
{
    //实例化
    QPainter painter(this);
    QImage img;
    img.load(":/picture/3.png");

    //修改像素点
    for (int i = 100;i < 200; i++) {
        for (int j = 100;j < 200; j++) {
            QRgb rgb = qRgb(0,0,255);
            img.setPixel(i,j,rgb);
        }
    }

    painter.drawImage(0,0,img);
}

3>QPicture

OPicture核心特性:

  • 使用QPainter直接在上面进行绘制图形
  • 通过文件路径加载并显示图片.
  • 能够记录QPainter的操作步骤,
  • 独立于硬件的绘制系统,能够在不同系统之上提供一致的显示

注意:

QPicture加载的必须是自身的存档文件,而不能是任意的png,jpg等图片文件

QPicture类似于很多游戏的Replay功能

例如像war3这样的经典游戏,即使是一场60分钟的膀胱局,生成的replay文件,也不过几百个KB

此处的Replay功能并非是把整个游戏画面都录制保存下来,而是记录了地图中发生的所有事件(地图元素,玩家单位操作,中立生物行为等)

当回放Replay的时候其实就是把上述记录的事件再一条一条的执行一遍即可还原之前的游戏场景了

不了解游戏的同学,也可以理解成警察蜀黍录笔录,并通过笔录还原案发现场

如果要记录下QPainter的命令,首先要使用QPainter:begin()函数,将QPicture实例作为参数传递进去,以便告诉系统开始记录,记录完毕后使用QPainter:end()命令终止。如下示例:

 

d616210e26a9ac48b2d969fc9408f22a.png

#include "widget.h"
#include "ui_widget.h"
#include<QPicture>
#include<QPainter>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    QPicture pic;
    QPainter painter;
    painter.begin(&pic); // 开始往pic绘图设备上绘画
    painter.setPen(QPen(Qt::red)); // 设置画笔颜色为红色
    painter.drawEllipse(QPoint(200,200),100,100);
    painter.end();//结束绘画
    pic.save("D:\\C C++\\program\\QT\\QPicture\\picture\\pic.pic");
}

Widget::~Widget()
{
    delete ui;
}

void Widget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);

    //重现绘图指令
    QPicture pic;
    pic.load("D:\\C C++\\program\\QT\\QPicture\\picture\\pic.pic");
    painter.drawPicture(0,0,pic);
}

④界面优化

其他美化方式包括但不限于:

  • Qt动画
  • Qt3D图形
  • QQuick
  • 使用第三方控件库
  • Qt Design Studio

这里不做过多介绍了

 

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部