开始前创建一个Widget窗口应用(其默认宽400像素,高300像素,左上角为原点)。
首先正常绘制一个正方形:
- void Widget::paintEvent(QPaintEvent *)
- {
- QPainter p(this);
- p.setPen(Qt::blue);
- p.drawRect(0, 0, 100, 100);
- }
复制代码
效果如下图:
这个是没有问题的,因为现在的绘图设备就是Widget,其左上角就是原点(0, 0)点。现在我们使用setWindow来设置逻辑坐标矩形:
- void Widget::paintEvent(QPaintEvent *)
- {
- QPainter p(this);
- p.setPen(Qt::blue);
- p.drawRect(0, 0, 100, 100);
- p.setWindow(-50, -50, 100, 100);
- p.setPen(Qt::red);
- p.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 p(this);
- p.setPen(Qt::blue);
- p.drawRect(0, 0, 100, 100);
- p.setWindow(-50, -50, 100, 100);
- p.setPen(Qt::red);
- p.drawRect(0, 0, 20, 20);
- }
复制代码
运行效果如下图所示:
我们将绘制的红色矩形变小,可以明显看到,本应该是个正方形,现在却变成了长方形。就是因为上面说的比例变换造成的,那么怎么才能让它显示应有的形状呢,我们来设置视口:
- void Widget::paintEvent(QPaintEvent *)
- {
- QPainter p(this);
- p.setPen(Qt::blue);
- p.drawRect(0, 0, 100, 100);
- int side = qMin(width(), height());
- p.setViewport((width() - side)/2, (height() - side) /2, side, side);
- p.setWindow(-50, -50, 100, 100);
- p.setPen(Qt::red);
- p.drawRect(0, 0, 20, 20);
- }
复制代码
现在使用setViewport设置视口为一个正方形,就是Widget可是区域上最大的正方形,这样逻辑坐标和物理坐标进行比例变换的时候,红色矩形的宽和高就不会因为缩放的比例不同而发生变形了,如下图所示。
问题提出:那么为什么要修改这个逻辑坐标矩形?
这是为了便于我们绘图,因为我们一般绘图时只是想在标准的坐标系中应该绘制成什么样子,不会考虑不同绘图设备的具体坐标系(比如有的设备坐标原点在其左上角,有的在中心等等),也不会考虑窗口的大小不同而使用不同的代码(比如我们只想在一个宽100、高100的绘图区域的中心绘制一个高20、宽20的正方形,到底实际绘图设备的单位是像素、还是英寸、还是厘米,我们不用考虑)。
引申术语:窗口、视口
这里说的我们想象中的宽100、高100、原点在中心的绘图区域,就是逻辑坐标下的矩形,也就是使用setWindow设置的所谓的窗口(英文为Window,注意与窗口部件的窗口二字意义不同);而实际的绘图设备,比如这里的Widget部件,其可视化的区域上设置的一个矩形被称为视口(英文为viewport),默认就是可视化区域的大小,但是可以通过setViewport来设置。窗口与视口相对应,可以进行线性变换,这样,我们就可以通过先设置视口,再设置对应的窗口的方法,来确保我们的代码在标准的想象中的坐标系中绘制的图形,可以准确地显示在不同的绘图设备界面上。
|