[学习][笔记] qt5 从入门到入坟:<10>坐标系统


坐标系统

Qt 学习之路 2(28):坐标系统
Qt中坐标:窗口坐标,视口坐标

所谓坐标系统,也就是QPaintDevice上面的坐标。默认坐标系统位于设备的左上角,也就是坐标原点 (0, 0)。x 轴方向向右;y 轴方向向下。
将QPainter的逻辑坐标与QPaintDevice的物理坐标进行映射的工作,是由QPainter的变换矩阵(transformation matrix)、视口(viewport)和窗口(window)完成的。

在 Qt 的坐标系统中,每个像素占据 1×1 的空间。你可以把它想象成一张方格纸,每个小格都是1个像素。方格的焦点定义了坐标,也就是说,像素 (x, y) 的中心位置其实是在 (x + 0.5, y + 0.5) 的位置上。这个坐标系统实际上是一个“半像素坐标系”。我们可以通过下面的示意图来理解这种坐标系:
在这里插入图片描述

绘制矩形

当我们绘制矩形左上角 (1, 2) 时,实际绘制的像素是在右下方。

当绘制大于1个像素时,情况比较复杂:如果绘制像素是偶数,则实际绘制会包裹住逻辑坐标值;如果是奇数,则是包裹住逻辑坐标值,再加上右下角一个像素的偏移。
在这里插入图片描述

从上图可以看出,
1.如果实际绘制是偶数像素,则会将逻辑坐标值夹在相等的两部分像素之间;
2.如果是奇数,则会在右下方多出一个像素。

Qt 的这种处理,带来的一个问题是,我们可能获取不到真实的坐标值。由于历史原因,QRect::right()和QRect::bottom()的返回值并不是矩形右下角点的真实坐标值:QRect::right()返回的是
left() + width() – 1;QRect::bottom()则返回 top() + height() –1,上图的绿色点指出了这两个函数的返回点的坐标。
为避免这个问题,我们建议是使用QRectF。
QRectF使用浮点值,而不是整数值,来描述坐标。这个类的两个函数QRectF::right()和QRectF::bottom()是正确的。如果你不得不使用QRect,那么可以利用 x() + width() 和 y() + height() 来替代 right() 和 bottom() 函数。

坐标变换

QPainter是一个状态机。那么,有时我想保存下当前的状态:当我临时绘制某些图像时,就可能想这么做。当然,我们有最原始的办法:将可能改变的状态,比如画笔颜色、粗细等,在临时绘制结束之后再全部恢复。对此,QPainter提供了内置的函数:save()和restore()。save()就是保存下当前状态;restore()则恢复上一次保存的结果。这两个函数必须成对出现:QPainter使用栈来保存数据,每一次save(),将当前状态压入栈顶,restore()则弹出栈顶进行恢复。

Qt 提供了四种坐标变换:平移 translate,旋转 rotate,缩放 scale,扭曲 shear

平移 translate

旋转 rotate

缩放 scale

扭曲 shear

视口坐标和窗口坐标

Qt 的坐标分为逻辑坐标和物理坐标。
在我们绘制时,提供给QPainter的都是逻辑坐标。
之前我们看到的坐标变换,也是针对逻辑坐标的。

所谓物理坐标,就是绘制底层QPaintDevice的坐标。
单单只有逻辑坐标,我们是不能在设备上进行绘制的。要想在设备上绘制,必须提供设备认识的物理坐标。

Qt 使用 viewport-window 机制将我们提供的逻辑坐标转换成绘制设备使用的物理坐标,
方法是,在逻辑坐标和物理坐标之间提供一层“窗口”坐标。
视口是由任意矩形指定的物理坐标;
窗口则是该矩形的逻辑坐标表示。
默认情况下,物理坐标和逻辑坐标是一致的,都等于设备矩形。

窗口坐标(逻辑坐标)

PaintedWidget::PaintedWidget(QWidget *parent) :
    QWidget(parent)
{
    resize(400, 400);//设置了窗口的大小和标题
    setWindowTitle(tr("Paint Demo"));
}

void PaintDemo::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setWindow(0, 0, 200, 200);
    painter.fillRect(0, 0, 200, 200, Qt::red);
}

如代码 没setWindows时 红色矩形为窗体四分之一 ,设置之后,红色矩形为整个窗体。 为什么呢?
窗口为逻辑坐标,将400400的窗体映射为了200200,原本对应1像素的单位变成了对应2像素的单位,
20012001=200200 原本的四分之一
20022002 = 400400 正好是物理像素大小 fillRect以新单位为单位
400*400即铺满大小

补充:
translate()函数只是简单地将坐标原点重新设置.

setWindow()则是将整个坐标系进行了修改。这段代码的运行结果是将整个窗口进行了填充。

painter.translate(200, 200);

我们将坐标原点设置到 (200, 200) 处,横坐标范围是 [-200, 200],纵坐标范围是 [-200, 200]

painter.setWindow(-160, -320, 320, 640);

坐标原点也是在窗口正中心,但是,我们将物理宽 400px 映射成窗口宽 320px,物理高 400px 映射成窗口高 640px,此时,横坐标范围是 [-160, 160],纵坐标范围是 [-320, 320]

视口(物理坐标)

PaintedWidget::PaintedWidget(QWidget *parent) :
    QWidget(parent)
{
    resize(400, 400);//设置了窗口的大小和标题
    setWindowTitle(tr("Paint Demo"));
}

void PaintDemo::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
//    painter.setWindow(0, 0, 400, 400);//等同于默认
    painter.setViewport(0, 0, 200, 200);
    painter.fillRect(0, 0, 200, 200, Qt::red);
}

如代码所示,没setViewPort之前 红色矩形 为窗体四分之一 setViewPort之后 红色矩形为窗体十六分之一
为什么呢?
视口为物理坐标,将400400物理像素 压缩成了200200物理像素 新单位为原本0.5像素 2000.52000.5 =
100
100 像素 对应400*400的正好为十六分之一

总结

在这里插入图片描述
(窗口坐标)逻辑坐标 -》 窗体坐标 -》 (视口坐标)物理坐标
即setWindow():resize(400*400):setViewPort()

代码

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二进制怪兽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值