qt QPainter setViewport setWindow viewport window

使用qt版本5.15.2

引入viewport和window目的是用于实现QPainter画出来的内容随着窗体伸缩与不伸缩两种情况,以及让QPainter在widget上指定的区域(viewport)进行绘制/渲染(分别对应下方demo1,demo2,demo3)。

**setViewport用于指定在widget的哪块区域做为QPainter的渲染区;而setWindow用于为viewport指定的区域建立新的坐标系。**新坐标系的物理单位长度与widget中坐标系的物理单位长度是不一样的,拥有了新坐标系就可以将viewport指定的区域虚拟成一个窗口(window)来用了。

setviewport(QRect(x,y,width,height))/setviewport(int x,int y,int width,int height); //指定在widget的具体位置和区域作为viewport(视口),作为painter的操作区域,这里的x,y为widget坐标系下的坐标

setWindow(QRect(x,y,width,height))/setWindow(int x,int y,int window_width,int window_height); //设置窗口坐标系,以及对viewport指定的操作区域大小进行重新划分(新的划分不以像素为单位了,而是一个虚拟的长度单位)。类似于长度换算中将10cm重新划分为n份,那么n份的单位长度就不是cm了。这里的x,y是新坐标系下的坐标。

window中坐标系横轴的单位长度为像素单位( widget坐标系的长度单位)为viewport.width/window.width;window中坐标系的纵轴**单位长度单位长度换算为像素单位(**widget坐标系的宽度单位)为viewport.height/window.height

坐标换算

假设虚拟window坐标系的起始点位(w.x0,w.y0),window的size为(w.w,w.h);viewport指定区域的起始点坐标为(v.x0,v.y0),指定区域的size为(v.w,v.h);

那么window中的一个点p(w.x,w.y),(线性)映射 到widget坐标系下相对于 viewport的起始点的 坐标为

(v.x,v.y),(线性)映射 到widget下的坐标为(x,y),那么

v.x=(w.x+w.x0)*v.w/w.w

v.y=(w.y+w.y0)*v.h/w.h

x = v.x0+v.x = v.x0+(w.x+w.x0)*v.w/w.w

y = v.y0+v.y = v.y0+(w.y+w.y0)*v.h/w.h

QPainter如果没有setViewport,那么viewport的rect()为QRect(0,0,widget.width,widget.height),当widget改变大小时(resize),viewport的rect()也会跟着对应变化为QRect(0,0,widget.width,widget.height)。

QPainter如果没有setWindow,那么window的rect()与上面一样。

这样就保证了改变widget的size的时候,viewport和window的rect()保持一样并且跟着窗口大小变化!!这样QPainter内容的伸缩因子(v.w/w.w,v.h/w.h)是不变的。导致的结果就是QPainter绘制的内容不会随着widget窗口伸缩

当QPainter setViewport(rectValue)后,viewport的rect就定死了,不管widget如何改变,viewport的rect()都为rectValue。

setWindow对window的rect影响同上。

setViewport(rectValue1),表示在widget上划定了一块具体的区域。不管widget是否改变大小,是否移动,viewport就是占据着widget的这块区域,类似下面的viewport指定QRect(0,0,200,200)。

复制代码
用 ffmpeg(最新版本) 制作gif
ffmpeg -f gdigrab -i desktop -t 20 -r 10 -vf "crop=640:480:500:300,setpts=PTS-STARTPTS" E:/video/test.mp4 -y  //录制桌面,-t录制20秒,-r帧率为10,-vf指定视频滤镜crop(裁剪,参数为width:height:x:y), -y 覆盖式写入文件,按ctrl+c强制结束录制
ffplay -vf "drawtext=text='%{pts\:hms}':x=10:y=10:fontsize=40:fontcolor=red"  -i E:/video/1/test.mp4 //播放视频,并显示时间戳
ffmpeg -i E:/video/test.mp4 -ss 2 -t 8 -r 1 E:/video/1/out_%d.png -y    //提取图片序列,-ss 视频开始时间,-t指定时长,-r从视频中一秒区一帧 
ffmpeg -framerate 4 -i E:/video/1/out_%d.png E:/video/1/out.gif -y   //将图片序列组成gif,帧率为4
ffplay -loop -1 -i E:/video/1/out.gif  //循环播放gif进行查阅,按esc退出

//更多ffmpeg操作命令了解参考https://blog.csdn.net/qiushangren/article/details/132777272

setViewport之后一般要做setWindow操作,否则window()所得到的QRect会随着widget窗口缩放而变化,这会导致QPainter画出来的内容变化诡异。

做了setWindow操作但是不做setViewport操作,意思是以整个widget为viewport,让viewport的rect()的值随着widget窗口的resize而变化,就能让QPainter画出来的内容随着widget窗口变化而伸缩

QPainter中,除了setViewport() viewport()使用的坐标和单位长度是widget的坐标(与实际像素点完全匹配)和其坐标系的单位长度。其他所有的成员函数参数使用的坐标和单位长度都是QPainter中虚拟出来的window的坐标系下的坐标和单位长度。

复制代码
//demo 1
//既不做setWindow操作,也不做setViewport操作,让QPainter画出来的内容不随着窗口resize而伸缩
void Widget::paintEvent(QPaintEvent *event)        //假设widget的长宽为700x600
{
    QPainter painter(this);
    painter.drawRect(10,10,60,50);                 //在画布上画正四边形,起点为画布的(10,10),长宽为60,50.
}

----------------------
//demo 2
//做setWindow操作,但是不做setViewport操作,让QPainter画出来的内容随着窗口resize而伸缩
void Widget::paintEvent(QPaintEvent *event)        //假设widget的长宽为700x600
{
    QPainter painter(this);
    painter.setWindow(10,10,300,300);              //建立新坐标系,将(10,10)作为painter画布yy1的起点,yy1的长宽都为300(这里的单位不是像素)
    painter.drawRect(10,10,60,50);                 //在画布上画正四边形,起点为画布的(10,10),长宽为60,50.(这里的单位不是像素,而是window建立的新坐标系的单位)
}


//demo 3
//做setViewport操作,也做setWindow操作,让QPainter在widget上setViewport指定的区域内渲染/绘制。内容不会随着窗口resize而伸缩或移动
void Widget::paintEvent(QPaintEvent *event)        //假设widget的长宽为700x600
{
    QPainter painter(this);
    painter.setViewport(100,100,300,300)           //指定widgetQRect(100,100,300,300)区域作为viewport
    painter.setWindow(10,10,500,500);              //将viewport指定的区域重新做一次划分,并在viewport指定的区域上建立新坐标系(新坐标系单位不是像素了,而是虚拟出来的单位)。将widget的坐标(10,10)作为painter画布yy1的起点,yy1的长宽都为300
    painter.drawRect(10,10,60,50);                 //在画布上画正四边形,起点为画布的(10,10),长宽为60,50.(这里的单位不是像素,而是window建立的新坐标系的单位)
}
相关推荐
用户805533698032 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner2 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz7 天前
QML Hello World 入门示例
qt
xcyxiner10 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner11 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner11 天前
DicomViewer (添加模型类)3
qt
xcyxiner12 天前
DicomViewer (目录调整) 2
qt
xcyxiner12 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00614 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术14 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript