原文链接:Qt学习之路(28): 坐标变换

 
同很多坐标系统一样,QPainter的默认坐标的原点(0, 0)位于屏幕的左上角,X轴正方向是水平向右,Y轴正方向是竖直向下。在这个坐标系统中,每个像素占据1 x 1的空间。你可以把它想象成是一张坐标值,其中的每个小格都是1个像素。这么说来,一个像素的中心实际上是一个“半像素坐标系”,也就是说,像素(x, y)的中心位置其实是在(x + 0.5, y + 0.5)的位置上。因此,如果我们使用QPainter在(100, 100)处绘制一个像素,那么,这个像素的中心坐标是(100.5, 100.5)。
 
这种细微的差别在实际应用中,特别是对坐标要求精确的系统中是很重要的。首先,只有在禁止反走样,也就是默认状态下,才会有这0.5像素的偏移;如果使用了反走样,那么,我们画(100, 100)位置的像素时,QPainter会在(99.5, 99.5),(99.5, 100.5),(100.5, 99.5)和(100.5, 100.5)四个位置绘制一个亮色的像素,这么产生的效果就是在这四个像素的焦点处(100, 100)产生了一个像素。如果不需要这个特性,就需要将QPainter的坐标系平移(0.5, 0.5)。
 
这一特性在绘制直线、矩形等图形的时候都会用到。下图给出了在没有反走样技术时,使用drawRect(2, 2, 6, 5)绘制一个矩形的示例。在No Pen的情况下,请注意矩形左上角的像素是在(2, 2),其中心位置是在(2.5, 2.5)的位置。然后注意下有不同的Pen的值的绘制样式,在Pen宽为1时,实际画出的矩形的面积是7 x 6的(图出自C++ GUI Programming with Qt4, 2nd Edition):
在具有反走样时,使用drawRect(2, 2, 6, 5)的效果如下(图出自C++ GUI Programming with Qt4, 2nd Edition):
注意我们前面说过,通过平移QPainter的坐标系来消除着0.5像素的差异。下面给出了使用drawRect(2.5, 2.5, 6, 5)在反走样情况下绘制的矩形(图出自C++ GUI Programming with Qt4, 2nd Edition):
请对比与上图的区别。
 
在上述的QPainter的默认坐标系下,QPainter提供了视口(viewport)窗口(window)机制,用于绘制与绘制设备的大小和分辨率无关的图形。视口和窗口是紧密的联系在一起的,它们一般都是矩形。视口是由物理坐标确定其大小,而窗口则是由逻辑坐标决定。我们在使用QPainter进行绘制时,传给QPainter的是逻辑坐标,然后,Qt的绘图机制会使用坐标变换将逻辑坐标转换成物理坐标后进行绘制。
 
通常,视口和窗口的坐标是一致的。比如一个600 x 800的widget(这是一个widget,或许是一个对话框,或许是一个面板等等),默认情况下,视口和窗口都是一个320 x 200的矩形,原点都在(0, 0),此时,视口和窗口的坐标是相同的。
 
注意到QPainter提供了setWindow()和setViewport()函数,用来设置视口和窗口的矩形大小。比如,在上面所述的320 x 200的widget中,我们要设置一个从(-50, -50)到(+50, +50),原点在中心的矩形窗口,就可以使用
 
painter.setWindow(-50, -50, 100, 100);
 
其中,(-50, -50)指明了原点,100, 100指明了窗口的长和宽。这里的“指明原点”意思是,逻辑坐标的(-50, -50)对应着物理坐标的(0, 0);“长和宽”说明,逻辑坐标系下的长100,宽100实际上对应物理坐标系的长320,宽200。
 
或许你已经发现这么一个好处,我们可以随时改变window的范围,而不改变底层物理坐标系。这就是前面所说的,视口与窗口的作用:“绘制与绘制设备的大小和分辨率无关的图形”,如下图所示(图出自C++ GUI Programming with Qt4, 2nd Edition):
 
 
除了视口与窗口的变化,QPainter还提供了一个“世界坐标系”,同样也可以变换图形。所不同的是,视口与窗口实际上是统一图形在两个坐标系下的表达,而世界坐标系的变换是通过改变坐标系来平移、缩放、旋转、剪切图形。为了清楚起见,我们来看下面一个例子:
 
void PaintedWidget::paintEvent(QPaintEvent *event)

{

        QPainter
painter(this);

        QFont
font("Courier",
24);

        painter.setFont(font);

        painter.drawText(50,
50, "Hello,
world!");

        QTransform
transform;

        transform.rotate(+45.0);

        painter.setWorldTransform(transform);

        painter.drawText(60,
60, "Hello,
world!");

}

 
为了显示方便,我在这里使用了QFont改变了字体。QPainter的drawText()函数提供了绘制文本的功能。它有几种重载形式,我们使用了其中的一种,即制定文本的坐标然后绘制。需要注意的是,这里的坐标是文字左下角的坐标(特别提醒这一点,因为很多绘图系统,比如Java2D都是把左上角作为坐标点的)!下面是运行结果:
 
我们使用QTransform做了一个rotate变换。这个变换就是旋转,而且是顺时针旋转45度。然后我们使用这个变换设置了QPainter的世界坐标系,注意到QPainter是一个状态机,所以这种变换并不会改变之前的状态,因此只有第二个Hello,
world!被旋转了。确切的说,被旋转的是坐标系而不是这个文字!请注意体会这两种说法的不同。

qt 坐标变换的更多相关文章

  1. Qt学习之路(28): 坐标变换

    经过前面的章节,我们已经能够画出一些东西来,主要就是使用QPainter的相关函数.今天,我们要看的是QPainter的坐标系统.   同很多坐标系统一样,QPainter的默认坐标的原点(0, 0) ...

  2. 基于C/S架构的3D对战网络游戏C++框架 _04客户端详细设计与OpenGL、Qt基础

    本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): ...

  3. 每日一笔记之2:QT之坐标系统:

    以前一直多单片机开发,也没怎么使用过大的显示器,第一次学习,备忘: QT画图系统. 绘图,通过QPainter类实现. Qt的绘图系统对底层函数进行了良好的封装,使得在屏幕和设备的绘图功能可能使用相同 ...

  4. 《Linux与Qt程序设计》知识框架

    本文主要是通过一本书来大致了解Qt开发的框架,不对具体内容做详细分析. 1.首先弄清楚概念:定义->以自己的话理解是什么-> 实现的是什么功能->用在哪些地方 2.前面认识到的知识点 ...

  5. QT的Paint 系统

    下面对于QT的绘制系统做一个简要说明, 这个系统主要由三部分组成,  QPainter, QPaintDevice, QPaintEngine. QPainter 是一个绘制接口类,提供绘制各种面向用 ...

  6. Qt 学习之路:坐标系统

    在经历过实际操作,以及前面一节中我们见到的那个translate()函数之后,我们可以详细了解下 Qt 的坐标系统了.泛泛而谈坐标系统,有时候会觉得枯燥无味,难以理解,好在现在我们已经有了基础. 坐标 ...

  7. Qt 学习之路 :坐标系统

    在经历过实际操作,以及前面一节中我们见到的那个translate()函数之后,我们可以详细了解下 Qt 的坐标系统了.泛泛而谈坐标系统,有时候会觉得枯燥无味,难以理解,好在现在我们已经有了基础. 坐标 ...

  8. qt坐标系统

    #说明:坐标系统是由 QPainter控制的QPaintDevice是那些能够让 QPainter 进行绘制的“东西”(准确的术语叫做,二维空间)# 的抽象层(其子类有QWidget. QPixmap ...

  9. QT 二维图形 原理、发展及应用

    转载自 网易博客:sun的博客 http://zhouyang340.blog.163.com/blog/static/3024095920126710504178/ 2D绘图 Qt4中的2D绘图部分 ...

随机推荐

  1. pythonpipinstallpymongo报错

    1.安装pymongo模块,报错pip版本低,升级版本又报错找不到合适的版本,网友说网络问题,要使用国内的镜像源来加速:pip install pymongo -i http://pypi.douba ...

  2. Fiddler 过滤设置

    1.User Fiters启用     2.Action Action:Run Filterset now是否运行,Load Filterset加载,Save Filterset保存:   3.Hos ...

  3. BZOJ2649 : riddle

    题意同3495,但是内存限制收紧了,不能采用3495的前后缀优化建图的方式. 注意到“每个集合恰好选择一个点”可以放宽成“每个集合最多选择一个点”,对于最后求出的方案里,如果某个集合没选点,任选一个就 ...

  4. 神奇高效的Linux命令行

    一.为什么要学linux命令 Linux是由命令行组成的操作系统,精髓在命令行,无论图形界面发展到什么水平,命令行方式的操作永远是不会变的.Linux命令有许多强大的功能:从简单的磁盘操作.文件存取, ...

  5. IntelliJ IDEA 2016.2 配置Tomcat 运行Web项目

    1.可能会出现的问题 Run-->Edit Configurations 中点击"+"号没有tomcat server... 解决办法:File--->Setting- ...

  6. linux configure 应用

    linux下configure命令详细介绍 2018年01月11日 15:02:20 冷月霜 阅读数:705 标签: configure 更多 个人分类: 数据库技术   Linux环境下的软件安装, ...

  7. Java-IO 字节流的使用和效率比较

    打算做一个系列,前面讲了基本的字符流的用法,这篇博客介绍一下字节流的基本用法: 一.基本使用: 基本字节流: FileInputStream   FileOutputStream BufferedIn ...

  8. 关于ck中断控制器

    一.中断控制器 中断控制器模块包括 其使能寄存器,状态寄存器等. 中断使能寄存器为32bit,每一个bit 对应一个中断源,具体对应到硬件上线的连接 二.cpu怎样调用到中断 (1). 前置工作 首先 ...

  9. 20175324 2018-2019-2 《Java程序设计》第5周学习总结

    20175324 2018-2019-2 <Java程序设计>第5周学习总结 教材学习内容总结 抽象类和具体类的区别在于抽象类中有抽象方法而具体类中没有.且抽象类不能实例化. 接口:如果一 ...

  10. Winform 窗体获得焦点

    给窗体添加Shown事件 public void Form_Shown(object sender, EventArgs e) { this.Activate(); this.Focus(); //定 ...