【Qt】2D绘图之窗口-视口转换

00. 目录

01. 概述

在使用QPainter进行绘制时,会使用逻辑坐标进行绘制,然后再转换为绘图设备的物理坐标。逻辑坐标到物理坐标的映射由QPainter的worldTransform()函数和QPainter的viewport()以及window()函数进行处理。其中视口(viewport)表示物理坐标下指定的一个任意矩形,而窗口(window,与以前讲的窗口部件的概念不同)表示逻辑坐标下的相同的矩形。默认的,逻辑坐标和物理坐标是重合的,它们都相当于绘图设备上的矩形。

使用窗口—视口转换可以使逻辑坐标系统适合应用的要求,这个机制也可以用来让绘图代码独立于绘图设备。

02. 开发环境

Windows系统:Windows10

Qt版本:Qt5.15或者Qt6

03. 程序示例

3.1 创建一个Widget窗口应用(其默认宽400像素,高300像素,左上角为原点)。首先正常绘制一个正方形

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

    painter.setPen(Qt::blue);

    painter.drawRect(0, 0, 100, 100);

}

的绘图设备就是Widget,其左上角就是原点(0, 0)点。效果如下图所示。
在这里插入图片描述

3.2 使用setWindow来设置逻辑坐标矩形

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

    painter.setPen(Qt::blue);

    painter.drawRect(0, 0, 100, 100);

    //设置逻辑坐标
    painter.setWindow(-50, -50, 100, 100);
    painter.setPen(Qt::red);
    painter.drawRect(0, 0, 100, 100);
}

运行结果:
在这里插入图片描述

现在来说p.setWindow(-50, -50, 100, 100)的作用,它将逻辑坐标矩形(后面提到的术语window窗口)与我们现在的设备物理坐标矩形(后面提到的术语viewport视口)进行了线性映射,这里所说的设备物理坐标矩形就是我们可见的Widget的坐标,就是左上角为(0, 0)点,宽400,高300这样的矩形,线性映射的示意图如下:
在这里插入图片描述

也就是说,调用p.setWindow(-50, -50, 100, 100)之后,再次使用p进行绘制,那么坐标原点就不再是Widget的左上角了,而是到了其中心,以前绘制的宽100、高100的正方形,现在也会按比例变为宽400, 高300,也就是我们看到的这个红色矩形。

再来修改代码

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

    painter.setPen(Qt::blue);

    painter.drawRect(0, 0, 100, 100);

    //设置逻辑坐标
    painter.setWindow(-50, -50, 100, 100);
    painter.setPen(Qt::red);
    painter.drawRect(0, 0, 20, 20);
}

运行效果如下图所示
在这里插入图片描述

我们将绘制的红色矩形变小,可以明显看到,本应该是个正方形,现在却变成了长方形。就是因为上面说的比例变换造成的,那么怎么才能让它显示应有的形状呢,我们来设置视口:

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

    painter.setPen(Qt::blue);

    painter.drawRect(0, 0, 100, 100);

    //设置逻辑坐标
    int side = qMin(width(), height());
    painter.setViewport((width() - side) / 2, (height() - side) / 2, side, side);
    painter.setWindow(-50, -50, 100, 100);
    painter.setPen(Qt::red);
    painter.drawRect(0, 0, 20, 20);
}

现在使用setViewport设置视口为一个正方形,就是Widget可是区域上最大的正方形,这样逻辑坐标和物理坐标进行比例变换的时候,红色矩形的宽和高就不会因为缩放的比例不同而发生变形了,如下图所示。
在这里插入图片描述

04. 为什么要修改这个逻辑坐标矩形?

这是为了便于我们绘图,因为我们一般绘图时只是想在标准的坐标系中应该绘制成什么样子,不会考虑不同绘图设备的具体坐标系(比如有的设备坐标原点在其左上角,有的在中心等等),也不会考虑窗口的大小不同而使用不同的代码(比如我们只想在一个宽100、高100的绘图区域的中心绘制一个高20、宽20的正方形,到底实际绘图设备的单位是像素、还是英寸、还是厘米,我们不用考虑)。

05. 窗口和视口

这里说的我们想象中的宽100、高100、原点在中心的绘图区域,就是逻辑坐标下的矩形,也就是使用setWindow设置的所谓的窗口(英文为Window,注意与窗口部件的窗口二字意义不同);而实际的绘图设备,比如这里的Widget部件,其可视化的区域上设置的一个矩形被称为视口(英文为viewport),默认就是可视化区域的大小,但是可以通过setViewport来设置。窗口与视口相对应,可以进行线性变换,这样,我们就可以通过先设置视口,再设置对应的窗口的方法,来确保我们的代码在标准的想象中的坐标系中绘制的图形,可以准确地显示在不同的绘图设备界面上。

06. 附录

Qt帮助文档关键字:Window-Viewport Conversion

源码下载:【Qt】2D绘图之窗口-视口转换.rar

© 版权声明
THE END
喜欢就支持一下吧
点赞195 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容