Qt 70行代码实现控件任意拆分 选中控件水平垂直拆分 窗口分割

效果

Demo工程源码
https://download.csdn.net/download/qq_41673920/20217378

https://gitee.com/TANG_N/QSplitterDemo
Qt 70行代码实现控件任意拆分 选中控件水平垂直拆分 窗口分割_第1张图片

实现思路

我们需要两个接口
分割控件的接口,选中一个控件,在这个控件上一分为二
删除控件接口,选中一个控件,删除掉
QSplitter功能比较基础,利用QSplitter我们可以实现像QtCreator编辑器随意拆分的效果

先看窗口结构,总共有三种实现方式。绿色方框的是添加的控件QWidget,黑色的是拆分器QSplitter只有模型一的默认分割出来才是1:1。逐个解释一下

模型一
每个Widget都被单独的一个QSplitter装载,一个QSplitter最多装载两个QSplitter,这么做浪费了很多QSplitter,比如3号那个,其实一个QSplitter就能搞定了。但是这样的好处是每次新建都会1:1的拆分,后面两种模型都不能1:1拆分,不知道什么原因,有搞定的欢迎回复
Qt 70行代码实现控件任意拆分 选中控件水平垂直拆分 窗口分割_第2张图片

Qt 70行代码实现控件任意拆分 选中控件水平垂直拆分 窗口分割_第3张图片

模型二
相比模型一,已经节约了不少QSplitter,但是拆分的widget不是默认1:1的,思考这个模型,QSplitter还可以精简,每个QSplitter还是只能装两个
Qt 70行代码实现控件任意拆分 选中控件水平垂直拆分 窗口分割_第4张图片

Qt 70行代码实现控件任意拆分 选中控件水平垂直拆分 窗口分割_第5张图片

模型三
这个是一个Splitter可以装任意多个Widget,最节约内存,但是和模型二一样拆分后不是1:1的
Qt 70行代码实现控件任意拆分 选中控件水平垂直拆分 窗口分割_第6张图片

Qt 70行代码实现控件任意拆分 选中控件水平垂直拆分 窗口分割_第7张图片

模型一实现添加

Qt 70行代码实现控件任意拆分 选中控件水平垂直拆分 窗口分割_第8张图片

如上图,我们水平拆分绿色控件1,每一个控件需被一个Splitter装载(因为这样很方便,暂且这么实现),直接把2设置成水平拆分器,然后新建两个Splitter,分别装载选中的控件1,和新加的控件src,最后把新建的两个QSplitter装入2就完成了,如下图,是不是很简单
Qt 70行代码实现控件任意拆分 选中控件水平垂直拆分 窗口分割_第9张图片

Qt 70行代码实现控件任意拆分 选中控件水平垂直拆分 窗口分割_第10张图片

模型一实现删除

Qt 70行代码实现控件任意拆分 选中控件水平垂直拆分 窗口分割_第11张图片

删除就比较简单了,以上图为例,想删掉箭头所指绿色控件1,把1,2,3删除,然后把上边那么那个QSplitter填入3所占的空就ok了

Qt 70行代码实现控件任意拆分 选中控件水平垂直拆分 窗口分割_第12张图片
其他两种实现看代码吧

代码

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

你可能感兴趣的:(Qt,Qt,窗口分割,Qt拆分器,QSplitter,窗口拆分,窗口分割)