参考:
Qt中有三个坐标系
设备坐标系: 即Device坐标系。也是物理坐标系。即真实的的物理坐标系。
逻辑坐标系: 即用户坐标系。也就是说日常大家使用Qt的时候的坐标系。
窗口坐标系: 这个坐标系是QPainter
设置setWindow
以后的一个坐标系。
这三个坐标系,基本上就代表了常规的绘制引擎的三个坐标系。
那么三个坐标系,就代表可以用两次变换来实现了。
这个就是QPainter
中的setWindow() & setViewport()
的两个概念了
直接看下图
via https://doc.qt.io/qt-6/coordsys.html#window-viewport-conversion
OK,既然有了这些概念,那么我们就开始讲一下,坐标系的转换流程。
废话不多说
还是按照我的方式 & Qt的官方文档来讲吧
我自己的例子
画个图,描述下这三个坐标系
平时我们的三个坐标系都是相同的,都是水平方向是X轴,垂直方向是Y轴,坐标原点是左上角(0, 0)。
X轴从左到右增加,Y轴从上到下增加
Qt的Demo
设定,屏幕的DPI是96
三个坐标系重叠
先创建一个QWidget,然后设置其大小是(500, 500)
resize(500,500);
然后再重写他的PaintEvent事件
void QtWidgetsApplication1::paintEvent(QPaintEvent*e)
{
QPainter painter(this);
painter.drawLine(0,0,500,500);
}
那么表现
这里可以先重点说下
我们以普通用户(程序员)的角度来理解这个代码。因为有三个坐标系,所以Qt的代码全都是以逻辑坐标系为基础的。对于这个代码来讲
painter.drawLine(0,0,500,500);
drawLine的时候实际上就是以逻辑坐标系为准。这时候,三个坐标系是相等的,没有任何比例变化。大家可以理解为这三个坐标系是重叠的。
setWindow()
控制变量,其他的代码不变,我们只单独设置setWindow这个代码setWindow的作用,就是在物理坐标系不变的情况下,将逻辑坐标系进行缩放。
假定,我们的代码是这样的。将逻辑坐标扩大一倍,那么代码就是这样的
void QtWidgetsApplication1::paintEvent(QPaintEvent*e)
{
QPainter painter(this);
painter.setWindow(0,0,1000,1000);
painter.drawLine(0,0,500,500);
}
这时候我们的窗口就变成了这个样子。
也就是说,我的物理大小,并没有变,我通过更改逻辑坐标,(放大两倍的效果) 看起来将我的整个坐标系变大了。比如原来我可以通过
painter.drawLine(0,0,500,500);
来绘制对角。
经过
painter.setWindow(0,0,1000,1000)\\放大逻辑坐标系两倍
最后
painter.drawLine(0,0,500,500);\\只能绘制一半的效果。
painter.drawLine(0,0,1000,1000);
也就是,我们现在将用户的坐标系放大了两倍。这个就是setWindow的作用。
setViewport()
大家可以理解setViewport
的作用就是控制物理坐标系的。
比如官方代码
int side=qMin(width(),height());
int x=(width()-side/2);
int y=(height()-side/2);
painter.setViewport(x,y,side,side);
还要控制窗口的宽高,这时候就更难理解了。我的例子还是控制变量,假定Window不变。我们只更改ViewPort
还是那个例子,窗口大小(500, 500)。我们还是画对角线。这时候我们把代码改成
void QtWidgetsApplication1::paintEvent(QPaintEvent*e)
{
QPainter painter(this);
painter.setViewport(0,0,1000,1000)
painter.drawLine(0,0,250,250);
}
大家可以看现象,画线也变粗了。这是为啥呢?
很简单,painter.setViewport(0, 0, 1000, 1000)
这个代码相当于把整个物理坐标系翻倍了。也就是单位逻辑坐标变大了。
原来逻辑坐标画1个像素点,现在相当于画2个。
所以会有两个现象
小结:
Qt通过三个坐标系,来做到了窗口之间的变换 & 放大缩小。
那么工程上是如何使用的呢。一般来说viewport
这个跟当前物理DPI保持一致。
然后通过setWindow放大坐标系
如果你想把整个逻辑坐标系放大。那么就用setWindow()
还是看你当前的逻辑需求- 即逻辑坐标系的需求。
以这个为出发点,那么再去理解setWindow & setViewport
就很好理解了。