Search code examples
qtwidgetqsplitter

Reparenting a Qt widget


I have a WidgetA widget, which is an owner-drawn widget. It's currently placed in QMainWindow's QVBoxLayout. After clicking a button, I'd like to "detach" WidgetA from this QVBoxLayout, insert QSplitter into this QVBoxLayout and "readd" WidgetA to this QSplitter. All this without destroying WidgetA, so it will preserve its drawing context, etc.

So, currently I have this (only one widget in a window):

only one widget in a window

I'd like to put a QSplitter between WidgetA and QMainWindow, and create a new widget, WidgetB, so I'd end up with:

two widgets, split by QSplitter

Later I'd like it to split even further, so both WidgetA and WidgetB would still allow themselves to be detached and placed in a new QSplitter, so it would be possible to create f.e. this hierarchy:

three widgets, split by two QSplitters

And, to be complete, one more step:

four widgets, split by three QSplitters

I'm not very experienced in Qt, so what I'm trying to do may seem pretty obvious, but I couldn't find how to "reparent" widgets. Is this possible in Qt?


Solution

  • Please, see reparent example, may be it helps you:

    //MyMainWindow.h
    #include <QWidget>
    #include <QPainter>
    #include <QVBoxLayout>
    #include <QHBoxLayout>
    #include <QPushButton>
    #include <QSplitter>
    
    class MyWidget: public QWidget
    {
    public:
      MyWidget(QWidget* parent, int number)
        : QWidget(parent),
          m_number(number)
      {
    
      }
    
    private:
      virtual void paintEvent(QPaintEvent* e)
      {
        QWidget::paintEvent(e);
    
        QPainter p(this);
        p.fillRect( rect(), Qt::red);
        p.drawText( rect(), Qt::AlignCenter, QString::number(m_number) );
      }
    
    private:
      int m_number;
    };
    
    class MyMainWindow: public QWidget
    {
      Q_OBJECT
    
    public:
      MyMainWindow()
      {
        setFixedSize(300, 200);
    
        m_mainLayout = new QVBoxLayout(this);
        QHBoxLayout* buttonLayout = new QHBoxLayout;
        m_mainLayout->addLayout(buttonLayout);
    
        m_button = new QPushButton("Button", this);
        buttonLayout->addWidget(m_button);
    
        connect(m_button, SIGNAL(clicked()), this, SLOT(onButtonClickedOnce()));
    
        m_initWidget = new MyWidget(this, 1);
        m_mainLayout->addWidget(m_initWidget);
      }
    
    private slots:
      void onButtonClickedOnce()
      {
        m_button->disconnect(this);
    
        m_mainLayout->removeWidget(m_initWidget);
        QSplitter* splitter = new QSplitter(Qt::Horizontal, this);
        m_mainLayout->addWidget(splitter);
    
        splitter->addWidget(m_initWidget);
        MyWidget* newWidget = new MyWidget(splitter, 2);
        splitter->addWidget(newWidget);
      }
    
    private:
      QVBoxLayout* m_mainLayout;
      QWidget* m_initWidget;
      QPushButton* m_button;
    };
    
    //main.cpp
    
    #include <QtWidgets/QApplication>
    #include "MyMainWindow.h"
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        MyMainWindow mainWindow;
        mainWindow.show();
    
        return a.exec();
    }