一个例子搞懂qt绘图的三个坐标系,setWindow,setViewport,widget的大小,逻辑坐标系,物理坐标系的关系

每次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,如图所示

widget+Viewport
Widget+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坐标系中绘制的图像是这样的

logic coordinate坐标下绘制的效果

然后就该进行所谓的把setWindow后的区域映射到Viewport当中了,此时我们发现logic coordinate中的关键部分,也就是那个连接对角线的矩形没在setWindow当中,那也没关系,我们截图,然后把这个Window放缩到和Viewport一样大,并且严丝合缝就行。操作如下图

把logic coordinate中的window截下来,并且放缩到和Viewport一样大,然后把图盖上去

这里我们把图的颜色带上,注意前面图中白色线为示意,实际上并不可见,黄色线为标注,现在我们把不可见的线画虚线,标注去掉。最终的效果应该是下图

把右边logic坐标系下的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.(这里有点点绕,但是把图附在下面,自己捋一捋就清楚了,就是个简单的数学映射)

把右侧logic坐标系下的矩形映射到左侧Viewport方块中

实际代码执行的效果图如下

 

另外,由于Viewport对window进行了2倍的放大,实际上红色线的长度应该为100*2=200个像素。我这里由于电脑分辨率有1.25倍的放大,实际测量为200*1.25=250像素长度。

使用像素尺,量的实际长度和计数结果吻合
像素尺测量结果和计算结果吻合

 

 好了,就写到这里。希望大家通过理解这一个例子,把这几个坐标系搞明白了,也不枉我辛苦这一遭。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值