首页 > 其他分享 >理解Qt中的setViewport和setWindow

理解Qt中的setViewport和setWindow

时间:2023-09-04 15:59:39浏览次数:39  
标签:10 窗口 Qt setWindow 视口 100 setViewport painter

概念相关
Qt的2D变换中有 逻辑坐标(窗口) 和 物理坐标(视口)

划重点: 窗口(逻辑坐标)与视口(物理坐标)的关系:窗口的四个角会映射到视口的四个角,它们四个角之间一一对应,两者的比例是 1:1。
它们默认的状态下,逻辑坐标和物理坐标都是一一对应的,起始点都是(0,0),长度高度也一致即两者重合,对应上方两者关系的说明。

注意了,我们编程的时候用的都是逻辑坐标。
还有拥有逻辑坐标这个窗口,不是我们常说的windows窗口,逻辑坐标这个窗口是一个看不见的矩形。

绘图的时候,是在窗口上绘图的哦。

单独setWindow或setViewport会造成等比例缩小/放大的问题。

是不是找到什么感觉了,嘻嘻

这些都是我的个人理解,如果有大佬阅读觉得有错误的,请务必要指正哦~~

案例测试
直接做测试,我拿来做测试的widget大小为300*300。

当单独setWindow时
void QPainter::setWindow (int x, int y, int width, int height)
我用的setwindow函数是第二个重载,将(x,y)作为原点,并设置该窗口大小为(width*height)。
直接贴上代码:

void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);

//黑色为正常
painter.drawRect(10,10,100,100);

//绿色为setWindow
painter.setPen(Qt::green);

//将逻辑坐标的(10,10)作为逻辑坐标的原点
//(0,0) --> (10,10)
painter.setWindow(10,10,300,300);

painter.drawRect(10,10,100,100);

int Lx,Ly,Rx,Ry;
//输出窗口高度宽度等
qDebug() << "window width" << painter.window().width();
qDebug() << "window height" << painter.window().height();
Lx = painter.window().topLeft().x();
Ly = painter.window().topLeft().y();
Rx = painter.window().bottomRight().x();
Ry = painter.window().bottomRight().y();
qDebug() << QString("window TopLeft And BottomRight (%1,%2) , (%3,%4)" )
.arg(Lx).arg(Ly).arg(Rx).arg(Ry) << endl;

//输出视口高度宽度等
qDebug() << "viewport width" << painter.viewport().width();
qDebug() << "viewport height" << painter.viewport().height();
Lx = painter.viewport().topLeft().x();
Ly = painter.viewport().topLeft().y();
Rx = painter.viewport().bottomRight().x();
Ry = painter.viewport().bottomRight().y();
qDebug() << QString("viewport TopLeft And BottomRight (%1,%2) , (%3,%4)" )
.arg(Lx).arg(Ly).arg(Rx).arg(Ry);
qDebug() << "--------------------------";
}

void Widget::on_pushButton_clicked()
{
if(width() < 600 || height() < 600)
{
resize(width()+100,height()+100);
ui->label->setText(QString("当前大小为:%1 * %2").arg(width()).arg(height()));
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
运行效果图:


发现问题:

当改变窗体(widget)大小的时候绿色的矩形会正比例放大或缩小?
当放大的宽高不一致时绿色矩形原本的形状会变形?
放大窗体会使视口大小变大,窗口大小不变?
输出窗口和视口的height()和width()与输出的左上角、右下角计算出来的高度和宽度有1的误差?
发现规律:当我等比例放大窗体的时候,它们有以下规律。

窗口:300*300 --> 300*300
视口:300*300 --> 400*400 (放大widget相当于放大设备坐标)
矩形:(10,10)(100,100)-->(0,0)(130,130)
窗口的1约等于视口的‭1.3像素,将逻辑坐标的矩形放大1.3倍

视口:300*300 --> 500*500
矩形:(10,10)(100,100)-->(0,0)(165,165)
//计算器算的是‭1.666666666666667‬,不知道为啥取1.65
窗口的1约等于视口的‭1.65像素,将逻辑坐标的矩形放大1.65倍

视口:300*300 --> 600*600
矩形:(10,10)(100,100)-->(0,0)(200,200)
窗口的1约等于视口的2像素,将逻辑坐标的矩形放大2倍
1
2
3
4
5
6
7
8
9
10
11
12
13
1.当改变窗体(widget)大小的时候绿色的矩形会正比例放大或缩小。

答:当窗口和视图都没有被人为改变的时候,它们的比例默认都是1:1 。当我们修改了窗口后会根据窗口大小与视图大小进行计算和转换坐标,上面的规律也差不多能证明它们之间的关系了。
公式是: (矩形宽度 * (视口宽度/窗口宽度),矩形高度 * (视口高度/窗口高度)
这个公式只能计算右下角这个点的位置,而且精确度会有偏差,其实这个东西没个鸟用。
2.当放大的宽高不一致时绿色矩形原本的形状会变形。

答:解决这个问题就是让窗口和视口维持相同的宽高来防止变形。即让它们回到默认状态 1:1
//解决这个问题的方案,那个书里面也有:不变形矩形等比例缩放。

//qMin():比较参数1和参数2,将最小的值返回。
int side = qMin(width(),height());
int x = (width() - side()/2);
int y = (height() - side()/2);
painter.setViewport(x,y,side,side)
1
2
3
4
5
6
7
3.放大窗体会使视口大小变大,窗口大小不变。

答:
视口对应的是物理坐标,物理坐标也俗称设备坐标。设备就是大家都应该知道是什么吧,咱们的屏幕。
但是软件中的视口就是显示内容部分的窗口(widget),当我放大这个widget的时候显示区域变大了,视口那肯定也变大了呀。
窗口大小不变是因为我们在代码中已经固定好了这个窗口的大小,所以它就不会根据我们的窗体大小变化而变化了呀。
4.输出窗口和视口的height()和width()与输出的左上角、右下角计算出来的高度和宽度有1的误差。

答:参考3:QRect和QRectF
由于历史原因bottom()和right()函数返回的值偏离了矩形的真正的右下角:
right()函数返回left() + width() - 1, bottom()函数返回top() + height() - 1。
topRight()函数和bottomLeft()函数的x坐标和y坐标分别包含与真正的右下角和右下角相同的偏差。
单独setViewport(),正好与setWindow()相反
void QPainter::setViewport(int x, int y, int width, int height)
将视口的原点布置在(x,y)处,视口大小改为width*height。
void Widget::paintEvent(QPaintEvent *event)
{

QPainter painter(this);

//左上角
//painter.setWindow(0,0,100,100);
//将视口的原点设置为(10,10),大小为300*300
painter.setViewport(10,10,300,300);
painter.drawRect(0,0,100,100);
painter.setPen(Qt::red);
painter.drawRect(10,10,100,100);

int Lx,Ly,Rx,Ry;

qDebug() << "window width" << painter.window().width();
qDebug() << "window height" << painter.window().height();
Lx = painter.window().topLeft().x();
Ly = painter.window().topLeft().y();
Rx = painter.window().bottomRight().x();
Ry = painter.window().bottomRight().y();
qDebug() << QString("window TopLeft And BottomRight (%1,%2) , (%3,%4)" )
.arg(Lx).arg(Ly).arg(Rx).arg(Ry) << endl;

qDebug() << "viewport width" << painter.viewport().width();
qDebug() << "viewport height" << painter.viewport().height();
Lx = painter.viewport().topLeft().x();
Ly = painter.viewport().topLeft().y();
Rx = painter.viewport().bottomRight().x();
Ry = painter.viewport().bottomRight().y();
qDebug() << QString("viewport TopLeft And BottomRight (%1,%2) , (%3,%4)" )
.arg(Lx).arg(Ly).arg(Rx).arg(Ry);
qDebug() << "--------------------------";
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
当我们单独使用setViewPort()的时候视口的大小已经被我们给固定住了,当放大窗体的时候窗口将会变大,故而引起两者宽高不一致,导致矩形缩小,成反比例。

通过两个实例得出以下规律:

单独使用setWindow()宽高给常数后会固定窗口的大小,放大窗体的时候只能放大视口,放大缩小成正比。单独使用setViewPort()反之。
同时使用setViewport和setWindow
同时使用setViewport和setWindow才是正确的操作,这两者配合才能打出一套配合拳。

提出问题:

先设置了setWindow()改变了窗口,那逻辑坐标也会改变,那么我们接下来使用逻辑坐标setViewport()会不会受到影响?
矩形超出了窗口和视口的范围,那超出的还会显示出来吗?
同时设置之后,放大或缩小窗体还会有矩形放大或缩小么?
1. 先设置了setWindow()改变了窗口,那逻辑坐标也会改变,那么我们接下来使用逻辑坐标setViewport()会不会受到影响?

直接贴代码:

void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);

painter.setWindow(-10,-10,100,100);
painter.setViewport(0,0,100,100);
painter.drawRect(0,0,90,90);
}
1
2
3
4
5
6
7
8
效果图:


答:很明显,是有影响的。
2. 矩形超出了窗口和视口的范围,那超出的还会显示出来吗?

将绘制矩形的代码修改如下:

painter.drawRect(-10,-10,110,110);
1
答:当你运行之后会发现,还是会显示出来的,它们并不能抑制显示,这也是一个坑坑坑。
3. 同时设置之后,放大或缩小窗体还会有矩形放大或缩小么?

painter.setWindow(-10,-10,100,100);
painter.setViewport(0,0,100,100);
painter.drawRect(-10,-10,110,110);
1
2
3
答:
上面的代码都是用了常量,而且窗口和视口的大小一致,所以并不会产生放大或缩小。
窗口和视口的映射关系知道了吧,为什么单独设置setViewport或setWindow会产生放大缩小比例的问题,这里我还要提一个点,就是因为窗口和视口的宽高不一致,比例也会不一致,才会导致那样的问题出现。
但是我们有时候并不希望它们一直都是这么死板,矩形随窗体大小变化而等比例变化,这时参数中就不能使用常量了。解决方法已经在单独设置setWindow第二问里面了哦。
本文有参考1:三步理解Qt中的setViewport和setWindow

本文由参考2:QT 坐标系统理解


————————————————
版权声明:本文为CSDN博主「焕小谢」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_38832450/article/details/103478571

 

 

 

 

from:https://blog.csdn.net/qq_38832450/article/details/103478571

标签:10,窗口,Qt,setWindow,视口,100,setViewport,painter
From: https://www.cnblogs.com/im18620660608/p/17677267.html

相关文章

  • 小谈Qt的坐标系系统 - 3个坐标系,2个变换
    小谈Qt的坐标系系统Qt中有三个坐标系设备坐标系窗口坐标系逻辑坐标系设备坐标系:即Device坐标系。也是物理坐标系。即真实的的物理坐标系。逻辑坐标系:即用户坐标系。也就是说日常大家使用Qt的时候的坐标系。窗口坐标系:这个坐标系是QPainter设置setWindow以后的一个坐......
  • QT坐标系转换(将QPainter左上角为原点的坐标系转换为正常坐标系)
    没有复杂的变换,简单转化窗口坐标系,即可按我们正常熟知的坐标系进行绘图QPainter坐标系以左上角为原点,如下图 在这样的坐标系下绘图,位置这是倒过来的QPainterm_pPainter(this);   m_pPainter.setBrush(Qt::yellow);   m_pPainter.drawRect(0,0,50,50);   m......
  • VS+Qt工具vsaddin
    1.https://download.qt.io/official_releases/vsaddin/2.ToolsExtensions-VisualStudio 安装:C:\xxxx\VSIXInstaller.exexxx.vsix......
  • 【Qt初入江湖】Qt QSqlQueryModel 底层架构、原理详细描述
    鱼弦:全栈领域创作新星创作者、51CTO(Top红人+专家博主)、github开源爱好者(go-zero源码二次开发、游戏后端架构https://github.com/Peakchen) QtQSqlQueryModel是Qt中用于实现自定义SQL查询的模型类,它继承自QAbstractTableModel。QSqlQueryModel封装了对数据库查询结果的处理,可......
  • 【Qt初入江湖】Qt QSqlRelationalDelegate 底层架构、原理详细描述
    鱼弦:全栈领域创作新星创作者、51CTO(Top红人+专家博主)、github开源爱好者(go-zero源码二次开发、游戏后端架构https://github.com/Peakchen) Qt的QSqlRelationalDelegate类是用于在Qt模型/视图框架中使用带有外键关系的数据库表格数据的委托类。它提供了一组用于在表格视图......
  • Qt中两个QLabel标签控件重叠的方法
       在项目中遇到这样的问题,需要开发一个电池控件,显示电量同时又能以数字标注电量的多少。效果如下图所示:      通常在Qt中图片的显示是用的QLabel标签控件。根据以往MFC开发的经验,想当然的是两个标签控件重叠排放,下面的标签控件显示图片,上面的标签控件显示数字。但......
  • 记录centos stream 9 编译qt5.15.10源码
    开始装的一些依赖库没有记录gcc之类的,都是通过dnf安装的主要是make过程中出现的问题(qtwebengine)及其如何解决编译的命令如下./configure-prefix/home/kun/usr/Qt/5.15.10-opensource-confirm-licensemake-j16makeinstallconfigure阶段失败一般都是缺少,都是dnf解决的......
  • ESP8266透明串口转MQTT模块使用说明
    ESP8266透明串口转MQTT模块使用说明 更新历史日期撰写备注2023.9.2YTH       目录1    模块功能...22    串口驱动...23    快速验证功能...33.1    模块默认功能:...33.2    手机开启热点.......
  • Qt编译报错:multiple definition of
    解决方法一:在.pro文件下查看SOURCES+=和HEADERS+=也没有重复引入文件,删除重复的文件即可。解决方法二:把debug文件夹下的.o文件都删除,然后再编译下。解决方法三:如果.h文件中有类的定义和实现,则实现时在每个成员前加inline。  转载于:QT项目出现multipledefinitionof错误......
  • qt读取json文件
    Qt读取json数据文件步骤:本条记录未进行判断,只是针对自己在已知json数据文件下的读取1、打开文件QFliefile("设置路径");2、设置文件打开方式file.open(QFile::ReadOnly|WriteOnly|ReadWrite);3、读取文件数据QByteArrayall=file.readAll();4、关闭文件file.cl......