C++客户端Qt开发——界面优化(绘图)

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>绘制线段

①: 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>绘制矩形

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

3>绘制圆形

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

4>绘制文本

cpp 复制代码
#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)

画笔风格展示:

画笔使用

cpp 复制代码
#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助手查找画刷的格式。如下图示:

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

cpp 复制代码
#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

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

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

然后把图片都添加进去

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

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

  • QPainter类中提供了translate()函数来实现坐标原点的改变
  • 图片的放大和缩小 可以使用QPainter类中的drawPixmap()函数来实现。
  • 图片的旋转 使用的是QPainter类中的rotate()函数,它默认是以原点为中心进行旋转的。如果要改变旋转的中心,可以使用translate()函数完成。
cpp 复制代码
#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()函数原型

restore()函数原型

③特殊的绘图设备

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

1>QPixmap

QPixmap核心特性:

  • 使用QPainter直接在上面进行绘制图形.
  • 通过文件路径加载并显示图片,
  • 搭配QPainterdrawPixmap()函数,可以把这个图片绘制到一个QLabelQPushButton等控件上
  • 和系统/显示设备强相关,不同系统/显示设备下,QPixmap的显示可能会有所差别
cpp 复制代码
#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直接在上面进行绘制图形
  • 通过文件路径加载并显示图片
  • 能够针对图片进行像素级别的操作(操作某个指定的像素).
  • 独立于硬件的绘制系统,能够在不同系统之上提供一致的显示
cpp 复制代码
#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****对像素的修改

cpp 复制代码
#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()命令终止。如下示例:

cpp 复制代码
#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

这里不做过多介绍了

相关推荐
姑苏老陈5 分钟前
【Python基础】Python文件处理
开发语言·python·python文件操作
luoluoal7 分钟前
java项目之企业级工位管理系统源码(springboot)
java·开发语言·spring boot
ch_s_t9 分钟前
新峰商城之购物车(一)
java·开发语言
学步_技术33 分钟前
Python编码系列—Python工厂方法模式:构建灵活对象的秘诀
开发语言·python·工厂方法模式
Deryck_德瑞克1 小时前
Java集合笔记
java·开发语言·笔记
MengYiKeNan1 小时前
C++二分函数lower_bound和upper_bound的用法
开发语言·c++·算法
会发paper的学渣1 小时前
python 单例模式实现
开发语言·python·单例模式
学步_技术1 小时前
Python编码系列—Python桥接模式:连接抽象与实现的桥梁
开发语言·python·桥接模式
柴华松1 小时前
GPU训练代码
开发语言·python
好兄弟给我起把狙1 小时前
[Golang] Select
开发语言·后端·golang