首页 > 其他分享 >Qt窗口和视口解析(转)

Qt窗口和视口解析(转)

时间:2023-09-25 14:14:09浏览次数:38  
标签:窗口 Qt 变换 视口 坐标 解析 坐标系 painter

目录

 

坐标变换流程

  QPainter.drawRect(QRectF)绘制图形传入的是世界坐标,而后经过变换矩形变为窗口坐标,最后经过窗口-视口变换变为设备坐标。其中世界坐标系和窗口坐标系都属于逻辑坐标系,设备坐标系属于物理坐标。

世界坐标、窗口坐标和设备坐标

  • 世界坐标
      世界坐标也叫逻辑坐标,使用的单位叫做逻辑单位,在世界坐标系中的大小与显示设备大小无关,类似于数学中的单位长度。

  • 窗口坐标
      窗口坐标与世界坐标差在坐标变换上,如translate、rotate、scale、shear等。

  • 设备坐标
      设备坐标是物理坐标,设备的左上角为原点(QGraphicsView同),向右为x正方向,向下为y轴正方向。物理坐标系的第二象限为有效绘图区域,没有负坐标轴。显示器中,坐标单位通常为像素,打印机中,坐标单位通常为点。

  综上,三个坐标系中,世界坐标系和窗口坐标系是逻辑坐标系,与具体的设备大小没有关系,两者之间相差的是坐标变换,而设备坐标系也就是物理坐标系,第二象限是绘图的有效果区域,没有负坐标轴。

窗口和视口

  • 窗口
      窗口是窗口坐标系中的矩形框,窗口存在的意义是为了确定显示窗口坐标系中的哪部分区域。
      使用painter.setWindow(x,y,w,h)即可设置窗口的大小以及坐标系原点在窗口中的位置。默认情况下窗口与视口大小相同,并且原点都位于左上角。

  • 视口
      视口是设备环境中的一个矩形框,使用物理坐标,和设备大小密切相关,超出设备外的视口区域不予显示。视口存在的意义是为了将显示的内容显示在物理坐标系中的哪个矩形区域。
      使用painter.setViewPort(x,y,w,h)即可设置视口的大小以及视口在物理坐标系中的位置。

  • 关于绘图设备
      绘图设备常常有QWidget、QPixmap、QImage等。(另外感觉QGraphicsItem也可以作为绘图设备,使用paint函数绘图。)
  • 关于QGraphicsView和QGraphicsScene
      使用QWidget::paintEvent只能绘制简单的图形,Qt提供了可与用户交互的QGraphics绘图体系,图形项可移动、选中。view类似于绘图设备,但是view不能设置视口,scene的坐标系类似于逻辑坐标系,可以通过view.setSceneRect(QRectF)来选定scene中的部分区域显示在view中。

世界变换和窗口视口变换

  • 世界变换
      世界变换的目的是直接对逻辑坐标进行矩阵变换,常见的有translate、scale、rotate、shear。

  • 窗口视口变换
      用户输入的坐标一定是逻辑坐标,最终用来绘制的一定是经过窗口-视口变换后的视口坐标,也就是设备坐标(物理坐标)。
      如果不显示使用setViewPortsetWindow指定视口和窗口大小,默认的窗口和视口坐标原点都是(0,0),窗口和视口大小都是设备的长和宽。若设置了一个,那么未设置的仍然使用默认设置。
      窗口和视口变换关系实际上就是一对线性函数:

`X' = aX + b`
`Y' = cY + d`
其中,XY为窗口坐标,X'Y'为视口坐标。

QWidget、QGraphicsItem、QGraphicsView绘图

  在QWidget::paintEvet()中绘图,QWidget是绘图设备,左上角为物理坐标系的坐标原点。通过设置窗口setWindow()和设置视口setViewPort()来分别设置逻辑坐标系的绘制区域和物理坐标系的显示区域,超出物理坐标系的内容不予显示。在逻辑坐标系中通过坐标系变换实现绘制。
  在QGraphicsItem::paint()中可以绘制,Item的左上角默认是逻辑坐标系的原点,可通过painter的坐标系变换(如translate、scale、shear、rotate)实现与QWidget体系中相同的绘制。与QWidget不同的是,超出Item仍然能够显示。
  QGraphicsView间接继承于QWidget,因此可作为控件摆放在QWidget中,直接继承于QAbstractScrollArea,因此作为显示的窗口时,可以出现滚动条。View与QGraphicsScene搭配使用,Scene用于存放QGraphicsItem,默认逻辑坐标系的原点位于其中心,Item通过item::setPos()设置其在(场景)逻辑坐标系中的位置,通过item::setRect()设置其在自身局部坐标系中的位置,因此Scene场景的不同位置皆可放置Item。而View类似于视口,用于显示场景中的内容,通过view::setSceneRect()可设置显示哪部分场景区域,类似于设置窗口。但是View并不能设置显示在哪部分区域。

窗口与视口绘图测试

painter.save();

painter.setPen(Qt::red);
painter.drawRect(0,0, 200, 200);//可视化视口(红色)
painter.setViewport(0,0, 200, 200);

QPen pen = painter.pen();
pen.setStyle(Qt::DashLine);
pen.setWidth(3);
pen.setColor(Qt::blue);
painter.setPen(pen);
painter.setWindow(-100, -100, 200, 200);
painter.drawRect(-100, -100, 200, 200);//可视化窗口(蓝色)

painter.translate(50, 50);//平移(50,50)

painter.setPen(Qt::black);//绘制两个图形
painter.drawRect(-100, -100, 100, 100);
painter.drawRect(50, 50, 100, 100);

painter.restore();

总结:

  1. 视口setViewport(QRectF)传入的是QWidget的物理坐标,窗口setWindow(QRectF)传入的是逻辑坐标。视口和窗口是线性映射关系,因此蓝框和红色框会重合。
  2. 平移translate(50,50)操作,移动的是逻辑坐标系,原来的坐标系原点在蓝色窗口中央,平移后位于图示的红色坐标系。
  3. save和restore用于保存和恢复QPainter的变换

https://www.cnblogs.com/wsw2022/p/16983853.html

标签:窗口,Qt,变换,视口,坐标,解析,坐标系,painter
From: https://www.cnblogs.com/xihong2014/p/17727815.html

相关文章

  • C#中实现校验是否包含中文与http接口地址中解析ip和端口号
    场景Winform/CSharp中实现对Http接口地址、IP地址字符串格式/合法性校验:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/129616161在上面的基础上对某http接口地址(ip加端口号,示例http://127.0.0.1:9092)进行校验是否包含中文以及解析该地址获取ip和端口号博客:h......
  • HashMap源码解析
    HashMap简介HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键,但最多只允许一条记录的键为null。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。其内部通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长。HashMap是......
  • ArrayList源码解析
    ArrayList是基于List接口,大小可变数组的实现。实现了所有可选列表操作,并允许包括null在内的所有元素。除了实现List接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。下面我们来分析ArrayList的源代码,ArrayList继承体系结构如下:publicclassArrayList<E>extend......
  • Java 8 Lambda 表达式解析
    Lambda表达式,也可称为闭包,它是推动Java8发布的最重要新特性。使用Lambda表达式可以使代码变的更加简洁紧凑。坦白的说,初次看见Lambda表达式瞬间头就大了,为了更好的理解,我们可以把Lambda表达式当作是一种匿名函数(对Java而言这并不完全正确,但现在姑且这么认为),简单地说,就是......
  • Qt/C++音视频开发56-udp推流和拉流/组播和单播推流
    一、前言之前已经实现了rtsp/rtmp推流,rtsp/rtmp/hls/flv/ws-flv/webrtc等拉流,这种一般都需要依赖一个独立的流媒体服务程序,有没有一种更便捷的方式不需要这种依赖,然后又能实现推拉流呢,当然有的那就是udpp推流,其中udp推流还可以是组播或者单播推流,组播一般会选择224.0.0.1这个地址......
  • Java LinkedList与ArrayList源码解析:根本区别和表面区别的详解
    在Java中,LinkedList和ArrayList是两个常见的集合类。它们都实现了List接口,但它们在实现方式上有很大的区别。本篇博客将详细解析LinkedList和ArrayList的源码,解释它们的根本区别和表面区别,并提供详细的代码解释。LinkedList与ArrayList的根本区别:数据结构:LinkedList是基于链表......
  • 无法在web.xml或使用此应用程序部署的jar文件中解析绝对uri:[http://java.sun.com/jsp/
    今天解决了一个很早之前的问题!!!无法在web.xml或使用此应用程序部署的jar文件中解析绝对uri:[http://java.sun.com/jsp/jstl/core]之前一直以为是jar包不匹配,但是改了jar包之后连uri都分辨不出来了后来在网上查到是tomcat的问题,将tomcat的conf目录下的catalina.properties的tomc......
  • Java面向对象思想解析:如何编写出高质量的代码
    面向对象思想面向对象思想面向对象是一种符合人类思维习惯的编程思想。现实生活中存在各种形态不同的事物,这些事物之间存在着各种各样的联系。在程序中使用对象来映射现实中的事物,使用对象的关系来描述事物之间的联系,这种思想就是面向对象。提到面向对象,自然会想到面向过程,面向过程......
  • [转]Websocket 底层是 TCP 还是 UDP?白话版解析 TCP 和 UDP 传输过程
    原文地址:Websocket底层是TCP还是UDP?白话版解析TCP和UDP传输过程-掘金写在前面在前面陆陆续续写了好几篇数字孪生相关的文章,而其中所涉及的一个其他项目比较不常使用的技术,网络通讯协议Websocket,这个协议主要用于服务器定时向客户端推送数据,相比HTTP更加适合数字......
  • Transformer架构解析及其pytorch实现
    备注本文对Transformer架构的分析来源于论文AttentionisAllYouNeed以及部分其引用的论文,可以理解为对该论文的翻译以及相关内容的整理。本文对Transformer的实现基于Pytorch,但是不直接调用Pytorch封装的Transformer,而是手动实现Encoder和Decoder等;与Transformer......