每次Qt绘图,碰到所谓的逻辑坐标系(logic coordinate),世界坐标系(world coordinate),设备坐标系(device coordinate/ physice coordinate),以及qt文档中说的setWindow,setViewport时,都云里雾里。正所谓咱们都是念过小学的人,如果我不明白,那么一定是你没说清楚。即使你再复杂,大不了是一个矩阵运算而已,不可能搞不清楚。所以我利用一个晚上的时间,把这点东西梳理梳理,做做实验,并把结果分享给大家,希望看到这篇文字的人,不再陷于这点东西。
这点东西,无非就是要把这么大点的东西,绘制到多大的地方上去,超出去了,不显示,没超出去就显示而已。
所以,首先widget的size,即widget的width和height就是绘制的地方大小。
setViewport就是设置Viewport,即设置视口,也就是在widget的哪块区域上绘制。
setWindow就是把多大的东西,搁置在Viewport那个视口上。
来,举个复杂的例子,有以下几句代码你瞅一下
CustomRect::CustomRect(QWidget *parent)
: QWidget{parent}
{
resize(200,500);
}
void CustomRect::paintEvent(QPaintEvent *event)
{
QPainter p(this);
p.setViewport(50,50,100,100);
p.setWindow(100,50,50,200);
p.setPen(QPen(Qt::green,3));
p.drawRect(0,0,100,100);
p.drawLine(0,0,100,100);
p.drawLine(100,0,0,100);
p.setPen(Qt::red);
p.drawRect(0,0,width(),height());
}
逐句解释下,这个widget在初始化的时候,设置为宽200pix,高500pix。然后setViewport(50,50,100,100)即在这个widget的50,50处,宽100,高100的地方开一个viewport,如图所示
然后setWindow(100,50,50,200)把logical coordinate,即用户随便画的那个坐标系中的100,50起,宽50,高200的区域映射进该Viewport,此时Viewport的左上角对应logic coordinate的100,50位置,Viewport当前的宽就是logic coordinate的50,Viewport当前的高就是logic coordinate的200.那么logic coordinate所绘制的图像此时最终应该怎么展示出来呢。
我们看下logic coordinate下绘制了什么东西,
p.setPen(QPen(Qt::green,3));
p.drawRect(0,0,100,100);
p.drawLine(0,0,100,100);
p.drawLine(100,0,0,100);
p.setPen(Qt::red);
p.drawRect(0,0,width(),height());
这几句代码,用绿色的笔画了个连接对角线的100*100的矩形,又用红色的笔绘制了个200*500的框,记住此时经过setWindow,设置了100,50起,宽50,高200的区域映射到Viewport,所以当前的coordinate坐标系中绘制的图像是这样的
然后就该进行所谓的把setWindow后的区域映射到Viewport当中了,此时我们发现logic coordinate中的关键部分,也就是那个连接对角线的矩形没在setWindow当中,那也没关系,我们截图,然后把这个Window放缩到和Viewport一样大,并且严丝合缝就行。操作如下图
这里我们把图的颜色带上,注意前面图中白色线为示意,实际上并不可见,黄色线为标注,现在我们把不可见的线画虚线,标注去掉。最终的效果应该是下图
最终可见的部分,其实就是widget那么大的区域,本例中最终的图里,widget的区域,会包括部分截断的连对角线的矩形,以及一段红色的矩形上边和一段红色下边,并且,红色的矩形边的长度为Widget的宽,超出widget宽的部分被截掉。 并且可以计算下,红色线条的长度与截断矩形的短边长度比例。由于window的width=50部分映射到Viewport的width=100,因此,window实际上是放大了2倍。所以Viewport距离widget左侧50的宽度,映射到window的长度为25的地方,即截断矩形的宽度为25像素(logic 坐标系下),红色矩形宽度为截断矩形宽度+(200-50)/2=25+75=100(logic坐标系下),因此该比例为25:100=1:4.(这里有点点绕,但是把图附在下面,自己捋一捋就清楚了,就是个简单的数学映射)
实际代码执行的效果图如下
另外,由于Viewport对window进行了2倍的放大,实际上红色线的长度应该为100*2=200个像素。我这里由于电脑分辨率有1.25倍的放大,实际测量为200*1.25=250像素长度。
好了,就写到这里。希望大家通过理解这一个例子,把这几个坐标系搞明白了,也不枉我辛苦这一遭。