Qt坐标系统

目录

概述

渲染

逻辑表示

锯齿绘制

坐标转换

模拟时钟示例

 Window-Viewport转换


概述

坐标系统由QPainter类控制。与QPaintDevice和QPaintEngine类一起,QPainter构成了Qt绘画系统的基础。QPainter用于执行绘制操作,QPaintDevice是一个二维空间的抽象,可以使用QPainter在其上进行绘制,QPaintEngine提供了画家用于在不同类型设备上绘制的界面。

QPaintDevice类是可绘制对象的基类:它的绘制功能由QWidget、QImage、QPixmap、QPicture和QOpenGLPaintDevice类继承。绘制设备的默认坐标系统起源于左上角。x值向右增大,y值向下增大。在基于像素的设备上,默认单位是一个像素,在打印机上是一个点(1/72英寸)。

逻辑QPainter坐标到物理QPaintDevice坐标的映射是由QPainter的转换矩阵、视口和“窗口”处理的。逻辑坐标系统和物理坐标系统默认重合。QPainter还支持坐标变换(例如旋转和缩放)。

渲染

逻辑表示

一个图元的大小(宽度和高度)总是对应于它的数学模型,忽略渲染它的笔的宽度

QRect(QPoint(1, 2), QPoint(7, 6))QLine(QPoint(2, 7), QPoint(6, 1))
QLine(2, 7, 6, 1)
QRect(QPoint(1, 2), QSize(6, 4))
QRect(1, 2, 6, 4)

锯齿绘制

绘制时,像素渲染由QPainter::Antialiasing渲染提示控制。
RenderHint枚举用于指定QPainter的标志,这些标志可能被任何给定的引擎尊重,也可能不被尊重。QPainter::Antialiasing值表示引擎应该尽可能地消除锯齿的边缘,即通过使用不同的颜色强度平滑边缘。
但在默认情况下,painter是走样(有锯齿)的,其他规则也适用:当使用一个像素宽的笔渲染时,像素将被渲染到右边,并低于数学定义的点。例如:

QPainter painter(this);painter.setPen(Qt::darkGreen);
// Using the (x  y  w  h) overload
painter.drawRect(1, 2, 6, 4);
QPainter painter(this);painter.setPen(Qt::darkGreen);
painter.drawLine(2, 7, 6, 1);

当使用具有偶数像素的笔进行渲染时,像素将围绕数学定义的点对称地渲染,而使用具有奇数像素的笔进行渲染时,多余的像素将像在一个像素的情况下一样呈现在数学点的右侧和下方。有关具体示例,请参见下面的QRectF图。

QRectF
逻辑表示一个像素宽的笔
两像素宽的笔三像素宽笔

请注意,由于历史原因,QRect::right()和QRect::bottom()函数的返回值偏离了矩形的真正右下角

QRect的right()函数返回left() + width() - 1,而bottom()函数返回top() + height() - 1。图中右下角的绿色点显示了这些函数的返回坐标。

我们建议你直接使用QRectF: QRectF类使用浮点坐标在平面中定义一个矩形来保证精度(QRect使用整数坐标),而QRectF::right()和QRectF::bottom()函数则返回真正的右下角。

或者,使用QRect,应用x() + width()和y() + height()来找到右下角,避免使用right()和bottom()函数。

抗锯齿的绘画
如果你设置了QPainter的抗锯齿渲染提示,像素将在数学定义的点的两边对称地渲染:

QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(Qt::darkGreen);
// Using the (x  y  w  h) overload
painter.drawRect(1, 2, 6, 4);
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(Qt::darkGreen);
painter.drawLine(2, 7, 6, 1);

坐标转换(矩阵变换)

默认情况下,QPainter在关联设备自己的坐标系统上操作,但它也完全支持仿射坐标变换。

您可以使用QPainter::scale()函数按给定的偏移量缩放坐标系统,您可以使用QPainter::rotate()函数顺时针旋转它,并且可以使用QPainter::translate()函数平移它(即向点添加给定的偏移量)。

noprotate()scale()translate()

你也可以使用QPainter::shear()函数围绕原点旋转坐标系统。所有的转换操作都是在QPainter的转换矩阵上进行的,你可以使用QPainter::worldTransform()函数来获取这个矩阵。矩阵将平面上的一个点变换为另一个点。

如果你需要反复使用相同的变换,你也可以使用QTransform对象以及QPainter::worldTransform()和QPainter::setWorldTransform()函数。你可以在任何时候通过调用QPainter::save()函数来保存QPainter的转换矩阵,该函数将矩阵保存在内部堆栈上。QPainter::restore()函数弹出它。

在各种绘图设备上重用相同的绘图代码时,经常需要转换矩阵。如果没有变换,结果将与绘制设备的分辨率紧密绑定。打印机的分辨率很高,例如每英寸600点,而屏幕的分辨率通常在每英寸72到100点之间。

模拟时钟示例

Analog Clock示例展示了如何使用QPainter的转换矩阵绘制自定义小部件的内容。
我们建议在进一步阅读之前编译并运行此示例。特别是,尝试将窗口大小调整为不同的大小。

Analog Clock Window Example | Qt GUI 5.15.17

void AnalogClockWindow::render(QPainter *p)
{static const QPoint hourHand[3] = {QPoint(7, 8),QPoint(-7, 8),QPoint(0, -40)};static const QPoint minuteHand[3] = {QPoint(7, 8),QPoint(-7, 8),QPoint(0, -70)};QColor hourColor(127, 0, 127);QColor minuteColor(0, 127, 127, 191);p->setRenderHint(QPainter::Antialiasing);p->translate(width() / 2, height() / 2);int side = qMin(width(), height());p->scale(side / 200.0, side / 200.0);

我们转换坐标系统,使点(0,0)位于小部件的中心,而不是位于左上角。我们还将系统按side / 100进行缩放,其中side是小部件的宽度或高度,以最短的为准。我们希望时钟是方的,即使设备不是方的。
这将给我们一个200 × 200的正方形区域,原点(0,0)在中心,我们可以在上面绘图。我们绘制的内容将显示在适合小部件的最大可能的正方形中。

    QTime time = QTime::currentTime();p->save();p->rotate(30.0 * ((time.hour() + time.minute() / 60.0)));p->drawConvexPolygon(hourHand, 3);p->restore();

我们通过旋转坐标系统并调用QPainter::drawConvexPolygon()来绘制时钟的时针。多亏了旋转,它指向了正确的方向。

多边形被指定为一个交替的x、y值数组,保存在静态变量hourHand中(在函数开始时定义),它对应四个点(2,0)、(0,2)、(- 2,0)和(0,-25)。

对代码周围的QPainter::save()和QPainter::restore()的调用保证了接下来的代码不会被我们使用的转换操作干扰。

    p->save();p->rotate(6.0 * (time.minute() + time.second() / 60.0));p->drawConvexPolygon(minuteHand, 3);p->restore();

我们对时钟的分针也是这样做的,分针由四个点(1,0)、(0,1)、(- 1,0)和(0,-40)定义。这些坐标指定了一个比分针更细更长的指针。

    p->setPen(minuteColor);for (int j = 0; j < 60; ++j) {if ((j % 5) != 0)p->drawLine(92, 0, 96, 0);p->rotate(6.0);}

最后,我们画出钟面,它由12条30度间隔的短线组成。最后,painter会以一种不太有用的方式旋转,但我们已经完成了绘制,所以这无关紧要。

有关转换矩阵的更多信息,请参阅 QTransform 文档。

 Window-Viewport转换

  • world坐标:转换(移动,缩放,旋转)后的逻辑坐标(没有转换则等于逻辑坐标)
  • window坐标:逻辑坐标
  • viewport坐标:物理坐标

当使用QPainter绘图时,我们使用逻辑坐标指定点,然后将其转换为绘图设备的物理坐标。

逻辑坐标到物理坐标的映射由QPainter的坐标转换worldTransform()(在上面坐标转换部分中描述)以及QPainter的viewport()window()处理。视口表示指定任意矩形的物理坐标。“窗口”在逻辑坐标中描述了相同的矩形。默认情况下,逻辑坐标系统和物理坐标系统是一致的,并且等价于绘制设备的矩形。

使用window-viewport转换,你可以让逻辑坐标系统符合你的偏好。该机制也可以用于使绘图代码独立于绘图设备。例如,你可以调用QPainter::setWindow()函数,将逻辑坐标从(-50,-50)扩展到(50,50),中心为(0,0):

QPainter painter(this);
painter.setWindow(QRect(-50, -50, 100, 100));//原点(左上角)是(-50,-50),宽高是100,那么右下角是(50,50);

现在,逻辑坐标(-50,-50)对应于绘图设备的物理坐标(0,0)。独立于绘图设备,您的绘图代码将始终在指定的逻辑坐标上操作。

通过设置"window"或视口矩形,可以对坐标进行线性变换。注意,“窗口”的每个角落都映射到视口的相应角落,反之亦然。因此,让视口和“窗口”保持相同的宽高比以防止变形通常是一个好主意:

int side = qMin(width(), height())
int x = (width() - side / 2);
int y = (height() - side / 2);painter.setViewport(x, y, side, side);//左上角是(50,50),宽高是100,右下角是(150,150)

如果我们将逻辑坐标系统设置为一个正方形,那么我们也应该使用QPainter::setViewport()函数将视口设置为一个正方形。在上面的示例中,我们使其等同于适合绘制设备矩形的最大正方形。通过在设置窗口或视口时考虑绘图设备的尺寸,可以使绘图代码独立于绘图设备。

请注意,窗口-视口转换只是一个线性转换,即它不执行裁剪。这意味着,如果你在当前设置的“窗口”之外绘制,你的绘制仍然会使用相同的线性代数方法转换到视口。

视口、“窗口”坐标转换 决定了逻辑QPainter坐标如何映射到绘制设备的物理坐标。默认情况下,坐标转换是单位矩阵,“窗口”和视口设置等同于绘制设备的设置,即世界、“窗口”和设备坐标系是等效的,但正如我们所看到的,系统可以使用坐标转换和窗口-视口转换来操纵。上面的插图描述了这个过程。

Coordinate System | Qt GUI 5.15.17

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/356088.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

提升教学效率的全方位解决方案

在现代教育环境中&#xff0c;教学管理的复杂性与日俱增。如何高效管理教学活动、优化教师资源、提升教学质量&#xff0c;是每个教育机构面临的重要挑战。搭贝教务教学管理系统提供了一套全面的解决方案&#xff0c;涵盖了巡检、调课代课、生源登记、监考、外派、作业发布、听…

LabVIEW回热系统热经济性分析及故障诊断

开发了一种利用LabVIEW软件的电厂回热系统热经济性分析和故障诊断系统。该系统针对火电厂回热加热器进行优化&#xff0c;通过实时数据监控与分析&#xff0c;有效提高机组的经济性和安全性&#xff0c;同时降低能耗和维护成本。系统的实施大幅提升了火电厂运行的效率和可靠性&…

2024会展行业发展趋势预测

在当今这个数字化浪潮汹涌的时代&#xff0c;会展行业也迎来了自己的变革时刻。 根据《2023中国会展主办机构数字化调研报告》&#xff0c;我们可以清晰地看到几个显著的趋势&#xff1a; 首先&#xff0c;数字化转型已经不再是一道选择题&#xff0c;而是必答题。 超过90%的…

LabVIEW Windows与RT系统的比较与选择

LabVIEW是一种系统设计和开发环境&#xff0c;广泛应用于各类工程和科学应用中。LabVIEW Windows和LabVIEW RT&#xff08;Real-Time&#xff09;是LabVIEW的两个主要版本&#xff0c;分别适用于不同的应用场景。以下从多个角度详细分析两者的区别&#xff0c;并提供选择建议。…

【大模型驯化-Prompt】企业级大模型Prompt调试技巧与batch批量调用方法

【大模型驯化-Prompt】企业级大模型Prompt调试技巧 本次修炼方法请往下查看 &#x1f308; 欢迎莅临我的博客个人主页 &#x1f448;这里是我工作、学习、实践 IT领域、真诚分享 踩坑集合&#xff0c;智慧小天地&#xff01; &#x1f387; 免费获取相关内容文档关注&#x…

网上预约就医取号系统

摘 要 近年来&#xff0c;随着信息技术的发展和普及&#xff0c;我国医疗信息产业快速发展&#xff0c;各大医院陆续推出自己的信息系统来实现医疗服务的现代化转型。不可否认&#xff0c;对一些大型三级医院来说&#xff0c;其信息服务质量还是广泛被大众所认可的。这就更需要…

@ModelAttribute

基础知识 1.ModelAttribute注解源码&#xff0c;从中可以知道&#xff0c;该注解可以标注在参数上和方法上 2.应用场景&#xff1a;先大致有个概念&#xff0c;可以用来存储项目根路径 3.介绍&#xff1a;ModelAttribute 是 Spring 框架中的一个注解&#xff0c;用于在 Spring …

Linux Centos 环境下搭建RocketMq集群(双主双从)

1、下载rocketmq的包 下载 | RocketMQ 2、配置环境变量 1、编辑环境变量文件&#xff1a;vim /etc/profile2、加入如下配置&#xff1a; #rocketmq 4.9.8 ROCKETMQ_HOME/home/rocketmq/rocketmq-4.9.8 export PATH${ROCKETMQ_HOME}/bin:${PATH}3、刷新配置&#xff1a;source…

修复kazam意外中断的视频文件

0. Problem 在用kazam录视频的过程中&#xff0c;PC意外重启了&#xff0c;然后kazam没有把文件自动转换成MP4&#xff0c;而是存为以下两个文件&#xff1a; kazam_xxxxx.movie kazam-xxxxx.movie.mux这两个文件一个0k&#xff0c;另一个是有size的&#xff0c;但是没办法直…

计算机组成原理 | 计算机系统概述

CPI:(Clockcycle Per Instruction)&#xff0c;指每条指令的时钟周期数。 时钟周期&#xff1a;对CPU来说&#xff0c;在一个时钟周期内&#xff0c;CPU仅完成一个最基本的动作。时钟脉冲是计算机的基本工作脉冲&#xff0c;控制着计算机的工作节奏。时钟周期 是一个时钟脉冲所…

Elk安装及使用

es安装及使用 单机版安装 集群安装 132 node-01 133 node-02 135 node-03 日志用户权限有问题 看日志 解决方案&#xff1a; 出现错误后&#xff0c;再次重启前&#xff0c;需要删除三个节点/data/下的内容 9300-http 9300-tcp logstasha安装及使用 Ssh错误 Yum安装默认路…

小巧悦耳的百元耳机,也有纯净的音乐享受,西圣AVA2体验

无论是居家休闲还是出门在外&#xff0c;音乐成为了许多人生活中不可或缺的一部分。特别是在拥有一款既经济又好听的蓝牙耳机之后&#xff0c;我们就可以在通勤路上和办公室里&#xff0c;隔绝外界干扰&#xff0c;找回属于自己的天地&#xff0c;提升生活品质。目前我用的是一…

【shell脚本速成】函数

文章目录 一、函数1.1、函数介绍1.2、函数定义1.3、函数调用 &#x1f308;你好呀&#xff01;我是 山顶风景独好 &#x1f388;欢迎踏入我的博客世界&#xff0c;能与您在此邂逅&#xff0c;真是缘分使然&#xff01;&#x1f60a; &#x1f338;愿您在此停留的每一刻&#xf…

LeetCode 19.删除链表的倒数第N个结点

链接 https://leetcode.cn/problems/remove-nth-node-from-end-of-list/description/ 题目: 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5…

JMeter的基本使用与性能测试,完整入门篇保姆式教程

Jmeter 的简介 JMeter是一个纯Java编写的开源软件&#xff0c;主要用于进行性能测试和功能测试。它支持测试的应用/服务/协议包括Web (HTTP, HTTPS)、SOAP/REST Webservices、FTP、Database via JDBC等。我们最常使用的是HTTP和HTTPS协议。 Jmeter主要组件 线程组&#xff08…

基于springboot实现影院订票系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现影院订票系统演示 摘要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本影院订票系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在…

python20 函数的定及调用

函数的定及调用 函数是将一段实现功能的完整代码&#xff0c;使用函数名称进行封装&#xff0c;通过函数名称进行调用。以此达到一次编写&#xff0c;多次调用的目的 用 def 关键字来声明 函数 格式&#xff1a; def 函数名(参数列表):函数体[:return 返回值是可选的&#xff0…

MySQL按小时分组统计日志记录数量

业务场景 MySQL按小时分组统计日志记录数量。最近需要统计一些日志流水&#xff0c;统计出打卡的高峰期&#xff0c;所以需要对日志流水按小时进行分组统计&#xff0c;统计出每半小时或者每小时内的打卡次数 按小时统计 这里使用DATE_FORMAT函数&#xff0c;然后再根据crea…

电脑怎么录制游戏视频?轻松捕捉每一帧精彩

随着游戏产业的蓬勃发展&#xff0c;越来越多的玩家不仅满足于在游戏世界中的探索与冒险&#xff0c;更希望将自己的游戏精彩瞬间记录下来&#xff0c;分享给更多的朋友。可是电脑怎么录制游戏视频呢&#xff1f;本文旨在为广大游戏爱好者提供一份详细的电脑游戏视频录制攻略&a…

excel基本操作

excel 若要取消在数据表中进行的所有筛选 步骤操作&#xff1a; 单击“数据”选项卡。在“排序和筛选”组中&#xff0c;找到“清除”按钮。点击“清除”按钮。 图例&#xff1a; 将文本文件的数据导入到Excel工作表中进行数据处理 步骤&#xff1a; 在Excel中&#xff0c…