动态增加分栏
本篇模拟Qt代码编辑器中的动态分栏功能,动态创建回收QSplitter
//mainwindow.cpp
MainWindow(){
QSplitter *sp = new QSplitter(this);
Widget *w = new Widget(sp);
sp->setHandleWidth(1);
sp->setChildrenCollapsible(false);
sp->addWidget(w);
setCentralWidget(sp);
resize(600,500);
}
//widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QSplitter>
#include <QComboBox>
#include <QStringListModel>
#include <QToolButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QResizeEvent>
#define ICONSIZE 20
class MyBtn: public QToolButton {
public:
MyBtn(QString icon,QLayout *layout, QWidget *parent): QToolButton{parent}{
setIcon(QIcon(icon)); setAutoRaise(true);
setFixedSize(ICONSIZE,ICONSIZE); layout->addWidget(this);
}
};
class Widget;
class WidgetPrivate: public QWidget{
public:
explicit WidgetPrivate(QWidget *parent= nullptr);
protected:
bool eventFilter(QObject *watched, QEvent *e) override;
private:
QStringListModel *model;
QComboBox *combox;
MyBtn *btnClose;
MyBtn *btnSplitV;
MyBtn *btnSplitH;
friend Widget;
};
class Widget: public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
protected:
virtual void resizeEvent(QResizeEvent *e) override;
protected slots:
void slot_Split(QObject *sender, Qt::Orientation orient);
void slot_UnSplit(QObject *sender);
private:
WidgetPrivate *d_ptr;
};
#endif // WIDGET_H
//widget.cpp
#include "testwidget.h"
WidgetPrivate::WidgetPrivate(QWidget *parent): QWidget{parent}
{
parent->installEventFilter(this);
QVBoxLayout *vlayout = new QVBoxLayout(this);
QHBoxLayout *hlayout = new QHBoxLayout();
hlayout->setContentsMargins(0,0,0,0);hlayout->setSpacing(1);
vlayout->setContentsMargins(0,0,0,0);vlayout->setSpacing(0);
QStringListModel *model = new QStringListModel({"<no document>"},this);
combox = new QComboBox(this); combox->setFixedHeight(ICONSIZE);
combox->setModel(model) ;hlayout->addWidget(combox);
btnSplitV = new MyBtn(":/split_v.svg",hlayout,this);
btnSplitH = new MyBtn(":/split_h.svg",hlayout,this);
btnClose = new MyBtn(":/close.svg", hlayout,this);
vlayout->addLayout(hlayout);
//QTextEdit *t=new QTextEdit(this);t->setStyleSheet("border:none;");vlayout->addWidget(t);
}
//auto-hide
bool WidgetPrivate::eventFilter(QObject *watched, QEvent *e)
{ //need parent->installEventFilter
if ( e->type()==QEvent::Enter ){ this->show(); return true;}
else if( e->type()==QEvent::Leave ){ this->hide(); return true;}
else return QObject::eventFilter(watched, e);
}
Widget::Widget(QWidget *parent): QWidget{parent}
{
d_ptr = new WidgetPrivate(this);
connect(d_ptr->btnSplitV,&QToolButton::clicked,this,[=](){slot_Split(this,Qt::Vertical);});
connect(d_ptr->btnSplitH,&QToolButton::clicked,this,[=](){slot_Split(this,Qt::Horizontal); });
connect(d_ptr->btnClose, &QToolButton::clicked,this,[=](){slot_UnSplit(this); });
setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
}
void Widget::resizeEvent(QResizeEvent *e)
{
d_ptr->resize(e->size().width(), d_ptr->height());
QWidget::resizeEvent(e);
}
void Widget::slot_Split(QObject *sender, Qt::Orientation orient)
{
QSplitter *parent_sp = qobject_cast<QSplitter*>(sender->parent() );
if(!parent_sp)return;
//1) add new splitter
QSplitter *subSP = new QSplitter(this);
subSP->setHandleWidth(1);
subSP->setOrientation(orient);
subSP->setChildrenCollapsible(false);
//2) old splitter add this new splitter as its child
int index = parent_sp->indexOf(this);
parent_sp->insertWidget(index,subSP);
//3) new splitter add parent's child
this->setParent(subSP);
subSP->addWidget(this);
//4) new splitter add a new widget
Widget* testW = new Widget(subSP);
subSP->addWidget(testW);
}
void Widget::slot_UnSplit(QObject *sender)
{
QSplitter *parent_sp = qobject_cast<QSplitter*>(sender->parent() );
if(!parent_sp) return;
// if("MainWindow" == parent_sp->parent()->objectName()) return; //keep the last one
// move sibline to parent before delete this widget and sub-splitter
int index = parent_sp->indexOf(this);
QWidget *sibline = parent_sp->widget(!index);
QSplitter *sp=(QSplitter*)parent_sp->parent();
if(sibline && sp){
index = sp->indexOf(parent_sp);
sp->replaceWidget(index,sibline);
sibline->setParent(sp);
}
//delete
parent_sp->deleteLater();
this->deleteLater();
}