窗口坐标为逻辑坐标,是基于视口坐标系的。

视口坐标为物理坐标,是基于绘图设备坐标系的

窗口坐标始终以视口坐标为最终目标进行映射:

QPainter::setWindow 修改了窗口位置和大小(左上角重新定义了一个数值和长度)

QPainter::setViewport 修改了视口位置和像素个数(左上角移动到相应位置和像素个数)

------------------------------------------------------------------------------------------------------------------------------------------------

看到Graphics View Framework的时候,被窗口,视口,场景坐标系,对象坐标系,世界坐标系,逻辑坐标,物理坐标等等概念彻底搞懵了。到底他们之间是什么关系呢?是怎样映射的呢?到现在小狼还没有搞懂,不过经过不断试验,有了一点点自己的理解。

QPainter的各种draw方法是基于窗口坐标系的。

窗口坐标为逻辑坐标,是基于视口坐标系的。视口坐标为物理坐标,是基于绘图设备坐标系的。没有做过改动的情况下,他们是一样的,都是以绘图设备(paint device,qwidget,qpixmap等都为绘图设备)大小为大小,左上角为原点(0,0)。

窗口:

窗口代表视口的区域,他始终以视口坐标为最终目标进行映射(这句话的意思到下面讲视口的时候会再讲),他的大小和逻辑位置可以通过QPainter::setWindow()设置,但是无论大小和逻辑位置设置为什么数值,他始终代表着整个视口。

例如你有一个实际大小为200×200像素的窗口,那么原始状态之下窗口大小也是200×200,视口大小也是200×200,,在0,0位置画一个大小为100×100的矩形的时候,他会占视口左上角的4分之一。
painter.drawRect(0,0,100,100);//draw 为单位长度

如果这时候我们通过QPainter::setWindow修改了窗口位置和大小,例如setWindow(-50,-50,100,100)

函数原型:
void QPainter::setWindow(int x, int y, int width, int height)

参数:
x:窗口左上角x坐标
y:窗口左上角y坐标
width:窗口长度(并非像素)
height:窗口高度(并非像素)

窗口代表的还是整个视口,但是映射的数值有所不同,这时候窗口的逻辑坐标(-50,-50)成为了视口坐标的(0,0),而窗口的逻辑大小成为了100×100的单位长度(这里用单位长度是因为窗口大小的长度并不固定,受视口大小影响),因为用100个单位长度代表原本物理大小的200像素,所以,每一个单位长度就是实际的2像素。因为QPainter是以窗口坐标为基础的,所以这时候画一个位置为(-50,-50),大小为 50,50的矩形。
painter.drawRect(-50,-50,50,50);
矩形还是占窗口的左上角的4分之一(下图左),而
painter.drawRect(0,0,50,50);
矩形占窗口右下角的4分之一。

而视口对应的则是物理坐标,没有改动的情况下,视口大小与绘图区大小一样,上面的例子中,视口的属性一直没有改变过,所以视口的左上角还是在绘图区的物理位置(0,0),在窗口坐标的(-50,-50)。大小为物理大小的

200×200像素,而为窗口坐标系下的100×100单位长度。

视口:

现在我们看看设置视口对绘图的影响,为了简单起见,先把上面的setWindow()一句注释掉,即现在窗口,视口是一样的。

现在来改变视口的属性,先用painter.setViewPort(0,0,100,100);
函数原型:
void QPainter::setViewport ( int x, int y, int width, int height )

参数:
x:设置视口左上角x坐标
y::设置视口左上角y坐标
width:设置视口长度(像素)
height:设置视口宽度(像素)

所以上面语句的作业就是把视口的的原点位置设置为绘图设备(这里是QDialog)的原点,大小改变为100,100。

那么现在是个什么情况呢?
现在我们把视口的坐标设置为绘图区的左上角(0,0)位置,大小设置为绘图区的一半,因为绘图区是(200×200),而我们把视口设置为(100×100)。即现在实际的绘图区为绘图设备的左上角的4分之一。

那么这时候我们再用
painter.drawRect(0,0,100,100);画一个矩形,实际显示是怎么样的呢?看下图:

绘制出来的是dialog的16分之一了,为什么会这样呢?

前面我们讲过窗口坐标始终以视口坐标为最终目标进行映射,而原来没有经过修改的窗口的属性为以左上角为原点,大小为200×200单位长度,我们修改视口大小为100×100像素后,窗口的200单位长度就映射到100像素的视口长度上,即每一单位长度为0.5像素,所以绘制出来的结果就是100×0.5=50像素,所以长和高都是dialog的4分之一,面积就是16分之一了。

这时候如果我们拖动dialog边界改变dialog的大小会怎么样呢?小狼原本的想法是画出来的矩形应该还是占总大小的16分之一,实际上这是错的。

void Lang::paintEvent(QPaintEvent *)
{
QPainter painter(this); qDebug()<<"after drag:"<<endl;
qDebug()<<painter.viewport().width();
qDebug()<<painter.viewport().height();
painter.setViewport(0, 0, 100 ,100 );
//painter.setWindow(-50,-50,100,100);
painter.drawRect(0,0, 100, 100);
}

先通过painter.viewport().width()和heigth()获取当前实际视口大小(paintEvent之前,视口会被重置为绘图设备实际大小)。如下图,当我们把dialog拖动为400×400大小时,矩形框变得更小了。

其实这很简单。因为在paintEvent之前窗口值也会重置为dialog(绘图设备)大小,所以这时候窗口大小为400×400单位长度,而视口我们还是再设定为100×100像素,所以这时候窗口大小的一单位长度为实际的100/400=0.25像素,所以画一个100×100单位长度的矩形时,实际大小时25×25像素,所以变得更小。


上图中我是用qq的截图功能进行测量,qq截图会给出当前截取图形的大小,正是25×25(圈的时候有所偏差).

最后再来看一个窗口和视口一起设置的例子.

void Lang::paintEvent(QPaintEvent *)
{
QPainter painter(this); qDebug()<<"after drag:"<<endl;
qDebug()<<painter.viewport().width();
qDebug()<<painter.viewport().height();
painter.setViewport(0, 0, 100 ,100 );
//painter.setWindow(-50,-50,100,100);
painter.drawRect(0,0, 100, 100);
}

这里设置窗口坐标(-50,-50)映射为视口的原点,把窗口100×100单位长度映射为视口的100×100像素大小
这时候窗口逻辑坐标-50,-50就是视口的坐标(0,0),也就是绘图设备的50,50坐标,所以窗口坐标(0,0)位置即绘图设备坐标的(100,100)
因为窗口坐标100单位长度映射到视口坐标的100像素,所以上图的painter.drawRect(0,0, 50, 50);一句绘制出了的结果就是在绘图设备的(100,100)位置绘制一个50×50像素的矩形。

总结:

要得到QPainter绘图的真正位置,要经过两步

第一步:
窗口坐标转换为视口坐标,转换公式为:
vp_width / win_width * (draw_x - win_x)
其中vp_width为视口长度,win_width为窗口长度,draw_x为实际要绘制的x左上坐标,win_x为窗口的x左上坐标,y坐标同理

窗口大小转换为视口大小,转换公式为:
draw_width * vp_width / win_width
draw_width为要绘制的窗口长度,vp_width为视口长度,win_width为窗口长度

height同理

第二步:

视口坐标转换为绘图设备坐标,这一步就简单的进行相加就好了
实际坐标x=上一步转换来的视口坐标+vp_x
vp_x为视口的左上x坐标,实际坐标y同理

Qt5之坐标系统的更多相关文章

  1. Qt5 教程

    序 Qt 前言 Hello, world! 信号槽 自定义信号槽 Qt 模块简介 MainWindow 简介 添加动作 资源文件 对象模型 布局管理器 菜单栏.工具栏和状态栏 对话框简介 对话框数据传 ...

  2. Qt5图形视图框架的“俄罗斯方块”(使用了QGraphicsView)

    Qt5 图形视图框架QGraphicsView 1.图形视图框架包含三大类:场景类(QGraphicsScene),视图类(QGraphicsView),图元类(QGraphicsItem): 2.对 ...

  3. QT5 QSS QML界面美化视频课程系列 QT原理 项目实战 C++1X STL

    QT5 QSS QML界面美化视频课程系列 QT原理 项目实战 C++1X STL 课程1   C语言程序设计高级实用速成课程 基础+进阶+自学 课程2   C语言程序设计Windows GDI图形绘 ...

  4. QT5利用chromium内核与HTML页面交互

    在QT5.4之前,做QT开发浏览器只能选择QWebkit,但是有过使用的都会发现,这个webkit不是出奇的慢,简直是慢的令人发指,Release模式下还行,debug下你就无语了,但是webkit毕 ...

  5. qt5中信号和槽的新语法

    qt5中的连接 有下列几种方式可以连接到信号上 旧语法 qt5将继续支持旧的语法去连接,在QObject对象上定义信号和槽函数,及任何继承QObjec的对象(包含QWidget). connect(s ...

  6. 使用AxisHelper帮助理解View and Data API中的坐标系统

    大家使用View and Data API做三维模型开发,必然首先要理解View and Data API的坐标系统,即XYZ三个轴向分别是怎么定义的.Three.js里面提供了一个AxisHelpe ...

  7. Ubuntu在wps-office等qt5程序下不能切换中文fcitx输入法的问题

    经检查,是缺了fcitx-qt的包.比如qt5的程序,需要一个叫fcitx-libs-qt5的包. 如果您在基于qt的程序下不能使用基于fcitx的中文输入法,请检查以下包是否已安装: sudo ap ...

  8. qt5中文代码编码编译问题

    qt中文代码用vs2010编译问题解决 总结说就是qt5默认UTF8不支持微软默认的ANSI(GB2312/GBK).解决办法是把中文字符串全部用 QString::fromLocal8Bit() 封 ...

  9. VS2010+Qt5.4.0 环境搭建(离线安装)

    原创作者:http://blog.csdn.net/solomon1558/article/details/44084969 前言 因项目需要Qt开发GUI,我根据网上资料及自己的经验整理了搭建vs2 ...

随机推荐

  1. Ubuntu21.04 / Linux Mint20.2 安装 TradingView分析软件

    TradingView 是我们经常使用的一个分析工具!在Linux 下安装桌面版,就可以爽快的用起来了,目前是Beta测试版,相信很快就会有正式版的 1.打开终端,执行下列命令,更新系统到最新 sud ...

  2. Java基础——类型转换注意事项及常见问题

    类型转换 由于Java是强类型语言,所以要进行有些运算的时候,需要用类型转换 低------------------------------------------------------------ ...

  3. python+pycharm+selenium+谷歌浏览器驱动 自动化环境部署(一)

    准备工作: 第一步:安装python.打开网址https://www.python.org/downloads/windows/     现在最新版本3.7,本人使用的是3.6. 第二步:安装pych ...

  4. Java-Dubbo学习及整合SpringBoot

    Dubbo架构 Dubbo是Java的RPC框架,具有三大核心功能:面向接口的远程方法调用,智能容错和负载均衡,以及服务的自动注册和发现 Dubbo架构图: 节点角色说明: 节点 说明 Provide ...

  5. Docker部署Zookeeper部署实践(1)

    Zookeeper可提供的服务主要有:配置服务.名字服务.分布式同步.组服务等 1. 抓取Zookeeper镜像 命令:docker pull zookeeper 2. 将Zookeeper镜像保存为 ...

  6. Shell-10-标准输入输出错误

    标准输入输出和错误 标准输入.输出和错误 重定向符号 示例 1 1 标准输出 2 错误输出 2 标准输出和错误输出同时定向到一个文件中 >share.txt 2>&1 3 > ...

  7. Golang语言系列-13-常用内置包

    常用内置包 net/http包 http请求和响应 http服务端 main.go文件 package main import ( "fmt" "io/ioutil&qu ...

  8. 你知道那些JVM性能调优

    设定堆内存大小 -Xms :堆初始空间大小 -Xmx : 堆内存最大限制. 设置新生代大小.新生代不宜太小,否则会有大量对象涌入老年代 -XX:NewSize : 新生代大小 -XX:NewRatio ...

  9. css生成彩色阴影

    通常用css生成单色或者同色系的的阴影(box-shadow),其实可以通过巧妙的利用 filter: blur 模糊滤镜,可以生成渐变色或者说是颜色丰富的阴影效果,如图: 原理: 利用伪元素,生成一 ...

  10. 通俗易懂理解——dijkstra算法求最短路径

    迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径.它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止 ###基本思想 通过Dij ...