前言:
QT自身的自适应Layout运用起来,比较复杂,并且需要比较多的时间来调配置各种参数,特别是在原有界面上增加/减少一些控件时的修改,很多时候让人抓狂。本文介绍了一种比较方便的方法来实现这适应窗口大小。
这种方式简单来说就是在Widget创建时,把Widget的初始大小以及其中的控件及其初始大小记录下来,然后在Widget中重载resizeEvent,在此实现中根据Widget的当前大小与初始大小的比例,动态把其中的各控件进行放缩。
为了更方便的实现,可以把这个放缩功能定义在一个基类中,代码如下:
1. UsefulFunsEditor中定义一些公共性质的函数
//UsefulFunsEditor.h
#pragma once
#include <vector>
void NoteWidgetGeometry(std::vector<std::pair<QWidget*, QRect>>& tMap, QWidget* widget);
void ResizeWidget( QWidget* widget, const QRect& srcRect, float scale_x, float scale_y );
void ResizeWidgets( const std::vector<std::pair<QWidget*, QRect>>& tMap, const QSize& parentSrcSize, const QSize& parentDstSize )
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//UsefulFunsEditor.cpp
#include <QWidget>
//把控件保存入表中
void NoteWidgetGeometry(std::vector<std::pair<QWidget*, QRect>>& tMap, QWidget* widget)
{
if( widget == nullptr )
{
return;
}
std::pair<QWidget*, QRect> tPair;
tPair.first = widget;
tPair.second = widget->geometry();
tMap.push_back(tPair);
}
//控件放缩
void ResizeWidget( QWidget* widget, const QRect& srcRect, float scale_x, float scale_y )
{
QRect tRect = srcRect;
int top = tRect.top();
int bottom = tRect.bottom();
int left = tRect.left();
int right= tRect.right();
top *= scale_y;
bottom *= scale_y;
left *= scale_x;
right *= scale_x;
tRect.setRect(left, top, right-left+1, bottom-top+1);
widget->setGeometry(tRect);
//widget->setAutoFillBackground()
widget->setFixedSize(right-left+1, bottom-top+1);
}
//表中所有控件放缩
void ResizeWidgets( const std::vector<std::pair<QWidget*, QRect>>& tMap, const QSize& parentSrcSize, const QSize& parentDstSize )
{
if( tMap.empty() )
{
return;
}
if( parentSrcSize.width() <= 0 || parentSrcSize.height() <= 0 )
{
return;
}
float scale_x = (float)(parentDstSize.width())/parentSrcSize.width();
float scale_y = (float)(parentDstSize.height())/parentSrcSize.height();
auto itEnd = tMap.end();
QRect rect;
QRect srcRect;
QString name;
for( auto it = tMap.begin(); it != itEnd; ++it )
{
const std::pair<QWidget*, QRect>& tPair = *it;
QWidget* widget = tPair.first;
name = widget->objectName();
srcRect = widget->geometry();
ResizeWidget( tPair.first, tPair.second, scale_x, scale_y );
rect = widget->geometry();
}
}
用于缩放的Widget基类
头文件
/*
===================================================================
WidgetChildClean.h
纯静版,没有相关Parent设置
2022-10-22 edit by lgy
===================================================================
*/
#pragma once
#include <vector>
#include "QWidget"
class WidgetChildClean :public QWidget
{
public:
WidgetChildClean(QWidget *parent = 0, Qt::WFlags flags = 0);
virtual ~WidgetChildClean();
virtual void Update(int delta_ms);
virtual void Active();
protected:
virtual void InitWidgetGeometry();
virtual void resizeEvent(QResizeEvent * event);
protected:
QSize mBaseSrcSize;
std::vector<std::pair<QWidget*, QRect> > mChildrenRectsMap;
};
实现文件
#include "QResizeEvent"
#include "WidgetChildClean.h"
#include "UsefulFunsEditor.h"
WidgetChildClean::WidgetChildClean(QWidget *parent, Qt::WFlags flags):QWidget(parent, flags)
{
}
WidgetChildClean::~WidgetChildClean()
{
}
void WidgetChildClean::Update(int delta_ms)
{
}
void WidgetChildClean::Active()
{
show();
}
void WidgetChildClean::InitWidgetGeometry()
{
mBaseSrcSize = size();
}
void WidgetChildClean::resizeEvent(QResizeEvent * event)
{
QSize curSize = event->size();
ResizeWidgets(mChildrenRectsMap, mBaseSrcSize, curSize);
}
注意:resizeEvent会在每次变化大小时会有调用,我们重点是在新创建的Widget类时,把WidgetChildClean当作一个基类。
实现的例子,注:例子是直接从项目中拿出来的,有大量与项目相关的实现,读者需要只要把相关的地方修改为自己的代码即可,我懒得重新写一个可运行的例子了:
/*
===================================================================
WidgetBGRecordTable.h
2022-10-22 edit by lgy
===================================================================
*/
#pragma once
#include "ui_uiBGRecordTable.h"
#include "WidgetChildClean.h"
#include "MovieRecordDB.h"
class CControlClient;
class WidgetBGRecordTable : public WidgetChildClean
{
Q_OBJECT
public:
WidgetBGRecordTable(QWidget *parent = 0, Qt::WFlags flags = 0);
virtual ~WidgetBGRecordTable();
virtual void Update(int delta_ms);
virtual void Active();
void EmptyAll();
void ClearTree();
void FreshRecordHeader(const std::map<int, std::string>& idNameList);
void ShowRecordTree(const DateMovieRecordMap& records);
protected:
virtual void InitWidgetGeometry();
private:
private:
Ui::Form_BGRecordTable ui;
std::map<int, std::string> mIDNameMap;
};
#include "WidgetBGRecordTable.h"
#include "UsefulFunsEditor.h"
WidgetBGRecordTable::WidgetBGRecordTable(QWidget *parent, Qt::WFlags flags):WidgetChildClean(parent, flags)
{
ui.setupUi(this);
InitWidgetGeometry();
}
WidgetBGRecordTable::~WidgetBGRecordTable()
{
}
void WidgetBGRecordTable::Update(int delta_ms)
{
}
void WidgetBGRecordTable::Active()
{
}
void WidgetBGRecordTable::InitWidgetGeometry()
{
mBaseSrcSize = size();
WIDGET_GEOMETRY(treeWidget_Record);
}
void WidgetBGRecordTable::EmptyAll()
{
ui.treeWidget_Record->clear();
QTreeWidgetItem* item = ui.treeWidget_Record->headerItem();
int count = item->columnCount();
for( int i = 0; i < count; ++i )
{
item->setText(i, "");
}
}
void WidgetBGRecordTable::ClearTree()
{
ui.treeWidget_Record->clear();
}
void WidgetBGRecordTable::FreshRecordHeader(const std::map<int, std::string>& idNameList)
{
mIDNameMap = idNameList;
QTreeWidgetItem* head = ui.treeWidget_Record->headerItem();
int count = head->columnCount();
for( int i = 0; i < count; ++i )
{
head->setText(i, "");
}
head->setText(0, QString::fromWCharArray(L"时间"));
int i=0;
for( auto it = idNameList.begin(); it!=idNameList.end(); it++ )
{
i=i+1;
QString name = AsciiStrToQStr(it->second);
head->setText(i, name);
}
}
void WidgetBGRecordTable::ShowRecordTree(const DateMovieRecordMap& records)
{
ui.treeWidget_Record->clear();
if( records.empty() )
{
return;
}
for( auto rit = records.rbegin(); rit != records.rend(); ++rit )
{
QString qnum;
qnum.setNum(rit->first);
QStringList qstrList;
qstrList.append(qnum);
for( auto it = rit->second.begin(); it != rit->second.end(); it++ )
{
int id = it->first;
RecordDef d = it->second;
if( mIDNameMap.count(id)== 0 )
{
qstrList.append("0");
}
else
{
QString qstr_play;
qstr_play.setNum(d.play_c);
qstrList.append(qstr_play);
}
}
QTreeWidgetItem* item = new QTreeWidgetItem(ui.treeWidget_Record, qstrList);
ui.treeWidget_Record->addTopLevelItem(item);
}
}
初始图:
放缩后的图