【Qt】绘图

绘图

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

说明
QPainter "画家" 用来绘图的对象,提供了一系列 drawXXX 方法,可以允许我们绘制各种图形
QPaintDevice "画板" 描述了 QPainter 把图形画到哪个对象上,之前的 QWidget 也是一种 QPaintDevice
QPen "画笔" 描述了 QPainter 画出来的线是什么样的
QBrush "画刷" 描述了 QPainter 填充了一个区域是什么样的

QPainter



这里画笔的样式有以下几种:

QBrush

其中画刷的样式有以下几种:


例如使用 Qt::DiagCrossPattern

绘制图片

平移坐标轴:translate(x, y) 表示水平方向上平移 x 单位,垂直方向上平移 y 单位。窗口默认大小为800*600,所以 translate(800,600) 后,坐标原点就跑右下角了。
旋转坐标轴:rotate(angel) 表示将坐标原点旋转 angel 角度,单位是度。angel 为正数表示顺时针。

视口和窗口

视口是指绘图设备的任意一个矩形区域,它使用物理坐标系。我们可以只选取物理坐标系中的一个矩形区域来绘图,默认情况下,视口等于绘图设备的整个矩形区域。窗口与视口是同一个矩形区域,但是窗口是用逻辑坐标系定义的,窗口可以直接定义矩形区域的逻辑坐标范围。

如下图矩形区域就是代表绘图设备的物理大小和坐标范围,假设大小为300*200像素。取其中间的一个正方形区域作为视口,卡其色的正方形区域就是视口。在绘图设备的物理坐标系中,视口的左上角坐标为 (50,0), 右下角坐标为 (250,200)。

QPainter 的函数 setViewport() 用于定义视口,有两种参数形式,其函数原型定义如下:

void QPainter::setViewport(const QRect &rectangle)

void QPainter::setViewport(int x, int y, int width, int height)

其中,(x, y) 是视口左上角在物理坐标系中的坐标,width 是视口宽度, height 是视口高度。上图中的视口需使用下面的语句:

painter.setViewport(50, 0, 200, 200);

这表示从绘图设备的物理坐标系中的一个点(50, 0) 开始,取宽度 300,高度 200像素的一个区域作为视口。对于上图视口所表示的正方形区域,我们定义如上图所示的一个窗口,窗口坐标系的原点在正方形的中心,并设置正方形的逻辑边长为 100。QPainter 的函数 setWindow() 用于定义窗口,有两种参数形式,其函数原型如下:

void QPainter::setWindow(const QRect &rectangle)

void QPainter::setWindow(int x, int y, int width, int height)

其中,(x, y) 是窗口左上角的坐标,width 是窗口逻辑宽度, height 是窗口逻辑高度。上图中的窗口需使用下面的语句:

painter.setWindow(-50, -50, 100, 100);

这表示对应于视口的正方形区域,其窗口左上角的逻辑坐标是 (-50, -50),窗口宽度为 100,高度为 100.这里设置的窗口仍为一个正方形,使得从视口变换到窗口时,长和宽的比例是相同的。实际可以任意指定窗口的逻辑坐标范围,长和宽的比例不同也是可以的。

视口窗口使用实例

使用窗口坐标系的优点是:在绘图时只需按照窗口坐标系定义来绘图,而不用关注实际的物理坐标范围。例如在一个固定边长为 100 的正方形窗口内绘图,当实际绘图设备大小变化时,绘图的图形会自动相应改变大小。这样,绘图功能与绘图设备是分离的,绘图功能可适用于不同大小、不同类型的绘图设备。

取高度和宽度中较小的一边为正方形边长,且图形是自动缩放的。

代码如下:

cpp 复制代码
void Widget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    int W = width();
    int H = height();
    int side = qMin(W,H);
    QRect rect((W-side)/2,(H-side)/2,side,side);
    painter.drawRect(rect);
    painter.setViewport(rect);
    painter.setWindow(-100,-100,200,200);
    QPen pen;
    pen.setWidth(1);
    pen.setColor(Qt::red);
    pen.setStyle(Qt::SolidLine);
    pen.setCapStyle(Qt::FlatCap);
    pen.setJoinStyle(Qt::BevelJoin);
    painter.setPen(pen);

    for(int i = 0; i < 36; i++)
    {
        painter.drawEllipse(QPoint(50,0),50,50);
        painter.rotate(10);//画一个圆旋转10度
    }
}

增加渐变填充和叠加效果的设置:

代码如下:

cpp 复制代码
void Widget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    int W = width();
    int H = height();
    int side = qMin(W,H);
    QRect rect((W-side)/2,(H-side)/2,side,side);
    painter.drawRect(rect);
    painter.setViewport(rect);
    painter.setWindow(-100,-100,200,200);
    QPen pen;
    pen.setWidth(1);
    pen.setColor(Qt::red);
    pen.setStyle(Qt::SolidLine);
    pen.setCapStyle(Qt::FlatCap);
    pen.setJoinStyle(Qt::BevelJoin);
    painter.setPen(pen);

    //线性渐变
    QLinearGradient linearGrad(0,0,100,0);//从左到右
    linearGrad.setColorAt(0,Qt::yellow);//起点颜色
    linearGrad.setColorAt(1,Qt::green);//终点颜色
    linearGrad.setSpread(QGradient::PadSpread);//展布模式
    painter.setBrush(linearGrad);

    //设置组合模式
    painter.setCompositionMode(QPainter::CompositionMode_Difference);
//    painter.setCompositionMode(QPainter::RasterOp_NotSourceXorDestination);
//    painter.setCompositionMode(QPainter::CompositionMode_Exclusion);

    for(int i = 0; i < 36; i++)
    {
        painter.drawEllipse(QPoint(50,0),50,50);
        painter.rotate(10);//画一个圆旋转10度
    }
}

以上窗口视口内容及代码为王维波等老师的书籍 《Qt6 C++ 开发指南》中的内容。

相关推荐
max50060010 分钟前
Python 脚本实现数据可视化
开发语言·python·信息可视化
HL_LOVE_C13 分钟前
全面理解-c++11中的智能指针
开发语言·c++
亲爱的老吉先森18 分钟前
常见数据结构的C语言定义---《数据结构C语言版》
c语言·开发语言·数据结构
geovindu37 分钟前
java: framework from BLL、DAL、IDAL、MODEL、Factory using postgresql 17.0
java·开发语言·postgresql
007php0071 小时前
Docker、Ollama、Dify 及 DeepSeek 安装配置与搭建企业级本地私有化知识库实践
运维·服务器·开发语言·后端·docker·容器·云计算
众乐乐_20082 小时前
JVM栈帧中|局部变量表、操作数栈、动态链接各自的任务是什么?
java·开发语言·jvm
魏翾蒨2 小时前
VBA语言的数据可视化
开发语言·后端·golang
致奋斗的我们2 小时前
项目:利用rsync备份全网服务器数据
linux·运维·服务器·开发语言·github·rsync·openeuler
Bluesonli3 小时前
第 9 天:UE5 物理系统 & 碰撞检测全解析!
开发语言·学习·游戏·ue5·虚幻·unreal engine
魏翾蒨3 小时前
PHP语言的数据库交互
开发语言·后端·golang