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

简介: [学习][笔记] 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()

代码

相关文章
|
1月前
|
开发框架 Java 编译器
【Qt 元对象系统 01 】深入探索Qt的元对象系统:核心地位、功能与构成
【Qt 元对象系统 01 】深入探索Qt的元对象系统:核心地位、功能与构成
52 0
|
1月前
|
Linux 数据处理 C++
Linux系统编程 C/C++ 以及Qt 中的零拷贝技术: 从底层原理到高级应用(一)
Linux系统编程 C/C++ 以及Qt 中的零拷贝技术: 从底层原理到高级应用
78 0
|
1月前
|
XML 安全 C++
DBus类型系统以及在Qt和C++ 中的使用(二)
DBus类型系统以及在Qt和C++ 中的使用
44 0
|
1月前
|
XML 存储 Unix
DBus类型系统以及在Qt和C++ 中的使用(一)
DBus类型系统以及在Qt和C++ 中的使用
43 0
|
2月前
|
数据挖掘 C++
QT基础入门——项目案例(七)
QT基础入门——项目案例(七)
97 0
QT基础入门——项目案例(七)
|
2月前
|
API
QT基础入门——Qt事件(五)
QT基础入门——Qt事件(五)
54 0
QT基础入门——Qt事件(五)
|
2月前
|
Unix Java Linux
QT基础入门——认识与创建QT(一)
QT基础入门——认识与创建QT(一)
62 0
QT基础入门——认识与创建QT(一)
|
1月前
|
存储 Linux API
Linux系统编程 C/C++ 以及Qt 中的零拷贝技术: 从底层原理到高级应用(三)
Linux系统编程 C/C++ 以及Qt 中的零拷贝技术: 从底层原理到高级应用
31 1
|
1月前
|
消息中间件 Linux 数据处理
Linux系统编程 C/C++ 以及Qt 中的零拷贝技术: 从底层原理到高级应用(二)
Linux系统编程 C/C++ 以及Qt 中的零拷贝技术: 从底层原理到高级应用
32 1
|
3月前
|
编译器 C++
01QT元对象系统
一、元对象系统    元对象系统是一个基于标准C++的扩展,为Qt提供了信号与槽机制、实时类型信息、动态属性系统。 元对象系统的三个基本条件:
26 0

热门文章

最新文章

推荐镜像

更多