Demo工程源码
https://download.csdn.net/download/qq_41673920/20217378
https://gitee.com/TANG_N/QSplitterDemo
我们需要两个接口
分割控件的接口,选中一个控件,在这个控件上一分为二
删除控件接口,选中一个控件,删除掉
QSplitter功能比较基础,利用QSplitter我们可以实现像QtCreator编辑器随意拆分的效果
先看窗口结构,总共有三种实现方式。绿色方框的是添加的控件QWidget,黑色的是拆分器QSplitter只有模型一的默认分割出来才是1:1。逐个解释一下
模型一
每个Widget都被单独的一个QSplitter装载,一个QSplitter最多装载两个QSplitter,这么做浪费了很多QSplitter,比如3号那个,其实一个QSplitter就能搞定了。但是这样的好处是每次新建都会1:1的拆分,后面两种模型都不能1:1拆分,不知道什么原因,有搞定的欢迎回复
模型二
相比模型一,已经节约了不少QSplitter,但是拆分的widget不是默认1:1的,思考这个模型,QSplitter还可以精简,每个QSplitter还是只能装两个
模型三
这个是一个Splitter可以装任意多个Widget,最节约内存,但是和模型二一样拆分后不是1:1的
如上图,我们水平拆分绿色控件1,每一个控件需被一个Splitter装载(因为这样很方便,暂且这么实现),直接把2设置成水平拆分器,然后新建两个Splitter,分别装载选中的控件1,和新加的控件src,最后把新建的两个QSplitter装入2就完成了,如下图,是不是很简单
删除就比较简单了,以上图为例,想删掉箭头所指绿色控件1,把1,2,3删除,然后把上边那么那个QSplitter填入3所占的空就ok了
CSplitter.cpp
#include "CSplitter.h"
#include
#include
CSplitter::CSplitter(QWidget *parent) : QWidget(parent)
{
QHBoxLayout *pLayout = new QHBoxLayout(this);
pLayout->setContentsMargins(0,0,0,0);
}
/* @dst:将要分割的已存在的控件
* @src:新加的控件
* @orientation:分割方向
*/
void CSplitter::addWidget(QWidget *dst, QWidget *src, Qt::Orientation orientation)
{
if(!src)
return ;
if ((nullptr == dst) || (0 == this->layout()->count()))
{
QSplitter *pSplitter = new QSplitter(this);
pSplitter->addWidget(src);
this->layout()->addWidget(pSplitter);
}
else
{
QSplitter *pPSplitter = qobject_cast<QSplitter *>(dst->parentWidget());
if (!pPSplitter)
return ;
pPSplitter->setOrientation(orientation);
QSplitter *pSplitterDst = new QSplitter(this);
pSplitterDst->addWidget(dst);
QSplitter *pSplitterSrc = new QSplitter(this);
pSplitterSrc->addWidget(src);
pPSplitter->addWidget(pSplitterDst);
pPSplitter->addWidget(pSplitterSrc);
}
}
void CSplitter::removeWidget(QWidget *src)
{
if(!src || !src->parentWidget())
return ;
QSplitter *pPPSplitter = qobject_cast<QSplitter *>(src->parentWidget()->parentWidget());
if (nullptr == pPPSplitter)
{
if(qobject_cast<QSplitter *>(src->parentWidget()))
delete src->parentWidget(); //src & splitter
}
else
{
QSplitter *pUSplitter = (QSplitter *)pPPSplitter->widget(!pPPSplitter->indexOf(src->parentWidget())); //QSplitter只会装两个 index非0即1
QSplitter *pPPPSplitter = qobject_cast<QSplitter *>(pPPSplitter->parentWidget());
if (nullptr == pPPPSplitter) {
this->layout()->addWidget(pUSplitter);
} else {
pPPPSplitter->insertWidget(pPPPSplitter->indexOf(pPPSplitter),pUSplitter);
}
delete pPPSplitter; //删除src 删除pSplitter
}
qDebug()<<"开始打印剩余控件------------";
recursiveInstallEventFilter(this);
qDebug()<<"打印完成------------";
}
void CSplitter::addWidget2(QWidget *dst, QWidget *src, Qt::Orientation orientation)
{
if(!src)
return ;
if ((nullptr == dst) || (0 == this->layout()->count()))
{
QSplitter *pSplitter = new QSplitter(orientation,this);
pSplitter->addWidget(src);
this->layout()->addWidget(pSplitter);
}
else
{
QSplitter *pPSplitter = qobject_cast<QSplitter *>(dst->parentWidget());
if(pPSplitter->count() > 1){
QSplitter *pSplitter = new QSplitter(orientation,this);
pPSplitter->insertWidget(pPSplitter->indexOf(dst),pSplitter);
pSplitter->addWidget(dst);
pSplitter->addWidget(src);
}else{
pPSplitter->setOrientation(orientation);
pPSplitter->addWidget(src);
}
}
}
void CSplitter::removeWidget2(QWidget *src)
{
if(!src || !src->parentWidget())
return ;
QSplitter *pPSplitter = qobject_cast<QSplitter *>(src->parentWidget());
if(pPSplitter->count() > 1){
QWidget *pBWidget = pPSplitter->widget(!pPSplitter->indexOf(src));
QSplitter *pPPSplitter = qobject_cast<QSplitter *>(pPSplitter->parentWidget());
if(nullptr == pPPSplitter){
if(nullptr == qobject_cast<QSplitter *>(pBWidget))
{
delete src;
return ;
}else{
this->layout()->addWidget(pBWidget);
}
}else{
pPPSplitter->insertWidget(pPPSplitter->indexOf(pPSplitter),pBWidget);
}
}
delete pPSplitter;
qDebug()<<"开始打印剩余控件------------";
recursiveInstallEventFilter(this);
qDebug()<<"打印完成------------";
}
void CSplitter::addWidget3(QWidget *dst, QWidget *src, Qt::Orientation orientation)
{
if(!src)
return ;
if ((nullptr == dst) || (0 == this->layout()->count()))
{
QSplitter *pSplitter = new QSplitter(orientation,this);
pSplitter->addWidget(src);
this->layout()->addWidget(pSplitter);
}
else
{
QSplitter *pPSplitter = qobject_cast<QSplitter *>(dst->parentWidget());
if(orientation == pPSplitter->orientation()){
qDebug()<<"+++++"<<dst->size()<<dst->baseSize()<<dst->sizePolicy()<<dst->sizeHint()<<dst->minimumSize()<<dst->maximumSize();
qDebug()<<"+++++"<<src->size()<<src->baseSize()<<src->sizePolicy()<<src->sizeHint()<<src->minimumSize()<<src->maximumSize();
pPSplitter->insertWidget(pPSplitter->indexOf(dst) + 1,src);
for(int i = 0; i < pPSplitter->count(); i++){
pPSplitter->setStretchFactor(i,1);
}
}else{
QSplitter *pSplitter = new QSplitter(orientation,this);
// pSplitter->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
pPSplitter->insertWidget(pPSplitter->indexOf(dst),pSplitter);
qDebug()<<"-----"<<dst->size()<<dst->baseSize()<<dst->sizePolicy()<<dst->sizeHint()<<dst->minimumSize()<<dst->maximumSize();
qDebug()<<"-----"<<src->size()<<src->baseSize()<<src->sizePolicy()<<src->sizeHint()<<src->minimumSize()<<src->maximumSize();
// dst->resize(0,0);
// src->resize(0,0);
pSplitter->addWidget(dst);
pSplitter->addWidget(src);
qDebug()<<"-----"<<dst->size()<<dst->baseSize()<<dst->sizePolicy()<<dst->sizeHint()<<dst->minimumSize()<<dst->maximumSize();
qDebug()<<"-----"<<src->size()<<src->baseSize()<<src->sizePolicy()<<src->sizeHint()<<src->minimumSize()<<src->maximumSize();
// pSplitter->setStretchFactor(0,1);
// pSplitter->setStretchFactor(1,1);
}
}
}
void CSplitter::removeWidget3(QWidget *src,bool clearEmptySplitter)
{
if(!src || !src->parentWidget())
return ;
//清理空的Splitter
if(clearEmptySplitter)
{
QSplitter *pSrcSplitter = qobject_cast<QSplitter *>(src);
if(pSrcSplitter){
QWidget *parent = pSrcSplitter->parentWidget();
if(0 == pSrcSplitter->count())
delete pSrcSplitter;
removeWidget3(parent,true);
}
}
else
{
QSplitter *pPSplitter = qobject_cast<QSplitter *>(src->parentWidget());
delete src;
if(pPSplitter)
removeWidget3(pPSplitter,true);//递归查找空的父Splitter 并删除
}
qDebug()<<"开始打印剩余控件------------";
recursiveInstallEventFilter(this);
qDebug()<<"打印完成------------";
}
void CSplitter::recursiveInstallEventFilter(QObject *pObject)
{
if(pObject->children().count() > 0) {
foreach (QObject *objChild, pObject->children()) {
qDebug()<<"子控件"<<objChild;
recursiveInstallEventFilter(objChild);
}
}
}
CSplitter.h
#ifndef CSPLITTER_H
#define CSPLITTER_H
#include
#include
class CSplitter : public QWidget
{
Q_OBJECT
public:
explicit CSplitter(QWidget *parent = 0);
//第一种实现 这种实现在拆分的时候 可以1:1拆分
void addWidget(QWidget *dst,QWidget *src,Qt::Orientation orientation);
void removeWidget(QWidget *src);
//第二种实现 减少Splitter的用量 降低内存开销 但是默认拆分不是1:1 各种设置试了但没成功
void addWidget2(QWidget *dst,QWidget *src,Qt::Orientation orientation);
void removeWidget2(QWidget *src);
//第三种实现 最少的QSplitter使用 但是默认拆分不是1:1 各种设置试了但没成功
void addWidget3(QWidget *dst,QWidget *src,Qt::Orientation orientation);
void removeWidget3(QWidget *src, bool clearEmptySplitter = false);
void recursiveInstallEventFilter(QObject *pObject);
};
#endif // CSPLITTER_H