QT应用程序分辨率自适应
一、应用程序分辨率自适应
为了满足应用程序能在不同尺寸及分辨率的屏幕下能够正常的运行显示,就需要对不同的分辨率进行自适应,而且应用程序分辨率自适应的问题在应用UI设计布局以及UI代码编写阶段进行设计规划,如在界面完成后期再考虑分辨率问题可能需要更大的工作量,并且自适应效果不一定能达到要求。一般来说,应用程序的设计应该按照支持的最小分辨率来进行设计,在应用程序分辨率变化时应用程序中的各个元素进行尺寸的缩放以及位置的调整,同时增加或减少应用程序显示界面内容,同时还要考虑图片失真,控件变形,字体显示等问题。
对于Qt应用来说,官方并没有提供一整套完整的解决有效方案,因此Qt程序的分辨率自适应问题需要按照应用程序的要求,在程序中自己实现相应的控件适应,但是分辨率适配的大体思路都是一致的,即调整控件尺寸及位置以及修改界面元素显示内容,Qt程序又可分为QtWidget程序以及qml程序,下面分别描述这两部分程序的界面分辨力的自适应解决方案。
二、QtWidget中的分辨率自适应
在QtWidget中Qt已经提供有相应的解决方案来实现控件分辨率的自适应,即通过layout对控件进行布局来实现控件的自适应,此外还可以通过自定义QTWidget中控件的自适应策略来实现分辨率自适应,下面分别介绍这两种方法:
2.1layout布局
通过layout布局的方式对QtwWidget的分辨率自适应,即将需要将自适应的控件添加进layout布局中,当layout的父对象的尺寸变化时,layout会根据父对象相应的变化宽、高比例对布局中的控件进行缩放,以此来实现相应控件的分辨率自适应。
通过layout的方式实现控件的方式实现自动缩放使用简单,且无须关注其具体的实现细节,但是这种方式需要就界面刚开始布局时,就要需要采用layout的方式进行布局,但是对于已经完成且没有采用layout布局的界面,可在QtCreator设计器中将需要添加布局的控件选中,然后点击右键,选择栅格化即可。
但是在QtCreator Designer中添加的layout存在一个问题,如下图在Designer中添加一个Vertical Layout,layout中添加两个PushButton,当运行程序后,调整程序大小,中间的PushButton并不会随着窗口大小而进行缩放。
通过查看QtCreator中通过ui文件生成的头文件,即ui_widget.h中的代码可以发现,在QtDesigner中添加layout时,会给layout自动添加一个widget的父对象,即下图中的verticalLayoutWidget,因此verticalLayout会随着其父对象verticalLayoutWidget的大小变化,对其中的控件进行缩放调整,因此才会出现上面的程序窗口变化时,layout中的控件不会自动缩放。
对于上述情况,需要在窗口大小变化时先调整verticalLayoutWidget的位置及大小,这样verticalLayout就会随着窗口大小的变化而自动调整其中的控件,具体操作如下
重载widget的resizeEvent函数,依据窗口大小的变化调整动态verticalLayoutWidget
QWidget * resizeWidget=ui->verticalLayoutWidget;
QRect resizeRect=resizeWidget->rect();
static float baseWidth=400;
static float baseHeight=300;
static float widgetWidth=resizeRect.width();
static float widgetHeight=resizeRect.height();
static float widgetX=ui->verticalLayoutWidget-
>geometry().x();
static float widgetY=ui->verticalLayoutWidget->geometry().y();
qDebug()<<resizeRect<<widgetX<<widgetY;
float horRatio=this->rect().width()/baseWidth;
float verRatio=this->rect().height()/baseHeight;
//dajust the position of verticalLayoutWidget
resizeRect.setX(widgetX*horRatio);
resizeRect.setY(widgetY*verRatio);
//resize the verticalLayoutWidget
resizeRect.setWidth(widgetWidth*horRatio);
resizeRect.setHeight(widgetHeight*verRatio);
//set Geometry
resizeWidget->setGeometry(resizeRect);
对于控件的缩放和位置调整,都是依据程序窗口的变化来调整的,这里选用horRatio,verRatio两个变量来记录窗口的宽度方向和高度方向的缩放比例,对于verticalLayoutWidget的宽度和高度来说直接按窗口的缩放比例按等比例缩放即可,对于X,Y按比例缩放
resizeRect.setX(widgetX*horRatio);
resizeRect.setY(widgetY*verRatio);
2.1自定义控件缩放
利用layout对控件进行布局缩放使用简单,且无需关注内部细节,但是利用layout进行布局时,控件的位置和大小受布局的约束无法实现大小和位置的精确控制,对于界面又复杂布局要求时layout并不能满足使用要求,对于这部分控件只能自定义控件的缩放,在程序窗口缩放是实现分辨率的自适应。
具体的缩放规则与前面类似,在程序窗口尺寸变化时,即首先获得程序窗口的缩放比例horRatio,verRatio放,然后对各个控件的X,Y以及宽度width和高度height进行相应比例的缩放即可,但是对于每个单独的控件都进行自定义缩放,实现起来较复杂,因此需要采用通用的方法来对各个控件进行缩放。
由于大部分的可以控件都是继承于QWidget的,因此查找到程序中所有的QWidget对象,然后在实现相应的变换即可。Qt提供了findChildren方法可以查找特定类型的子对象,因此可以利用这个方法来实现查找QWidget的子对象,并进行自定义缩放:
首先定义结构体来存储控件的基本尺寸及位置
struct AutoResizeOriginalData
{
QRect data_rect;
QFont data_font;
};
//define a map to store the resize items
QMap<QWidget*,AutoResizeOriginalData> m_resizeMap;
然后在查找窗口中全部的QWidget对象,并记录其初始位置
QWidget *item=NULL;
AutoResizeOriginalData resizeData;
QRect tmp;
QList<QLabel*> _labelList=m_autoResizeObj->findChildren<QLabel *>();
for(auto it=_labelList.begin();it!=_labelList.end();it++)
{
item=*it;