找回密码
 立即注册
  • QQ空间
  • 回复
  • 收藏

Qt 2D绘图部分窗口、视口的研究

yafeilinux 2017-5-7 23:38 20523人围观 yafeilinux原创

版权声明

该文章原创于Qt开源社区www.qter.org),作者yafeilinux,转载请注明出处!可以到这里讨论该文章。


开始前创建一个Widget窗口应用(其默认宽400像素,高300像素,左上角为原点)。

首先正常绘制一个正方形:
  1. void Widget::paintEvent(QPaintEvent *)
  2. {
  3.     QPainter p(this);
  4.     p.setPen(Qt::blue);
  5.     p.drawRect(0, 0, 100, 100);
  6. }
复制代码


效果如下图:
01.jpg


这个是没有问题的,因为现在的绘图设备就是Widget,其左上角就是原点(0, 0)点。现在我们使用setWindow来设置逻辑坐标矩形:

  1. void Widget::paintEvent(QPaintEvent *)
  2. {
  3.     QPainter p(this);
  4.     p.setPen(Qt::blue);
  5.     p.drawRect(0, 0, 100, 100);

  6.     p.setWindow(-50, -50, 100, 100);
  7.     p.setPen(Qt::red);
  8.     p.drawRect(0, 0, 100, 100);
  9. }
复制代码

这时,效果如下图所示。
02.jpg


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


03.jpg


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


再来修改代码:


  1. void Widget::paintEvent(QPaintEvent *)

  2. {
  3.     QPainter p(this);
  4.     p.setPen(Qt::blue);
  5.     p.drawRect(0, 0, 100, 100);

  6.     p.setWindow(-50, -50, 100, 100);
  7.     p.setPen(Qt::red);
  8.     p.drawRect(0, 0, 20, 20);
  9. }
复制代码


运行效果如下图所示:


04.jpg


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


  1. void Widget::paintEvent(QPaintEvent *)
  2. {
  3.     QPainter p(this);
  4.     p.setPen(Qt::blue);
  5.     p.drawRect(0, 0, 100, 100);

  6.     int side = qMin(width(), height());
  7.     p.setViewport((width() - side)/2, (height() - side) /2, side, side);
  8.     p.setWindow(-50, -50, 100, 100);

  9.     p.setPen(Qt::red);
  10.     p.drawRect(0, 0, 20, 20);
  11. }
复制代码



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


05.jpg



问题提出:那么为什么要修改这个逻辑坐标矩形?

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




引申术语:窗口、视口

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





原作者: yafeilinux

yafeilinux和他的朋友们微信公众号二维码

微信公众号

专注于Qt嵌入式Linux开发等。扫一扫立即关注。

Qt开源社区官方QQ群二维码

QQ交流群

欢迎加入QQ群大家庭,一起讨论学习!


公告
可以关注我们的微信公众号yafeilinux_friends获取最新动态,或者加入QQ会员群进行交流:190741849、186601429(已满) 我知道了