5

I have an application that has 3 main widgets. I also have a pop-out QDockWidget. I'm trying to get the QDockWidget to dock into the right half of the bottom widget, but as you can see in the image below, the only places I can dock the window are on the edges of the application. How can I make it so that the QDockWidget window takes up the right half of the bottom widget?

enter image description here

Also, is there a way to have a QDockWidget be already docked upon opening the application instead of having it open separately in its own window?

EDIT: Using @Bertrand's answer below, here's what I wound up doing:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
  Q_OBJECT

public:
  explicit MainWindow(QWidget *parent = 0);
  ~MainWindow();


private:
  Ui::MainWindow *ui;
  void on_actionRestore_layout_triggered();
  QMainWindow* m_rightSideWindow;
  QDockWidget* m_dockWidget1;
  QDockWidget* m_dockWidget2;
  QDockWidget* m_dockWidget3;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QtWidgets>

MainWindow::MainWindow(QWidget *parent) :
  QMainWindow(parent),
  ui(new Ui::MainWindow),
  m_rightSideWindow(NULL),
  m_dockWidget1(NULL),
  m_dockWidget2(NULL),
  m_dockWidget3(NULL)
{
  ui->setupUi(this);
  QSplitter *splitter = new QSplitter(this);
      splitter->setOrientation(Qt::Horizontal);
      QTreeView* leftSideWidget = new QTreeView(this);

      m_rightSideWindow = new QMainWindow(this);
      m_rightSideWindow->setWindowFlags(Qt::Widget);
      m_rightSideWindow->layout()->setContentsMargins(3, 3, 3, 3);

      splitter->addWidget(leftSideWidget);
      splitter->addWidget(m_rightSideWindow);

      m_dockWidget1 = new QDockWidget("Dock 1", this);
      m_rightSideWindow->addDockWidget(Qt::TopDockWidgetArea, m_dockWidget1);
      m_dockWidget1->setTitleBarWidget(new QWidget()); // remove title bar
      m_dockWidget1->setAllowedAreas(Qt::NoDockWidgetArea); // do not allow to dock
      QTextEdit* textEdit1 = new QTextEdit(this); // put any QWidget derived class inside
      m_dockWidget1->setWidget(textEdit1);

      m_dockWidget2 = new QDockWidget("Dock 2", this);
      m_rightSideWindow->addDockWidget(Qt::BottomDockWidgetArea, m_dockWidget2);
      m_dockWidget2->setTitleBarWidget(new QWidget());
      m_dockWidget2->setAllowedAreas(Qt::NoDockWidgetArea);
      QTextEdit* textEdit2 = new QTextEdit(this);
      m_dockWidget2->setWidget(textEdit2);

      m_dockWidget3 = new QDockWidget("Dock 3", this);
      m_rightSideWindow->addDockWidget(Qt::BottomDockWidgetArea, m_dockWidget3);
      QTextEdit* textEdit3 = new QTextEdit(this);
      m_dockWidget3->setWidget(textEdit3);

      setCentralWidget(splitter);
}

MainWindow::~MainWindow()
{
  delete ui;
}

void MainWindow::on_actionRestore_layout_triggered()
{
    QList<QDockWidget*> list = findChildren<QDockWidget*>();
    foreach(QDockWidget* dock, list)
    {
        if(dock->isFloating())
            dock->setFloating(false);
        m_rightSideWindow->removeDockWidget(dock);
        if (dock == m_dockWidget1)
            m_rightSideWindow->addDockWidget(Qt::TopDockWidgetArea, m_dockWidget1);
        else
            m_rightSideWindow->addDockWidget(Qt::BottomDockWidgetArea, dock);
        dock->setVisible(true);
    }
    m_rightSideWindow->splitDockWidget(m_dockWidget2, m_dockWidget3, Qt::Horizontal);
}
earth
  • 945
  • 1
  • 10
  • 27

1 Answers1

7

You can dock a QDockWidget on a QMainWindow or another QDockWidget.

To get the desired layout embed a sub QMainWindow on the right side of your main window, and use it as a QWidget with setWindowFlags(Qt::Widget):

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QtWidgets>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QSplitter *splitter = new QSplitter(this);
    splitter->setOrientation(Qt::Horizontal);
    QTreeView* leftSideWidget = new QTreeView(this);

    m_rightSideWindow = new QMainWindow(this);
    m_rightSideWindow->setWindowFlags(Qt::Widget);
    m_rightSideWindow->layout()->setContentsMargins(3, 3, 3, 3);

    splitter->addWidget(leftSideWidget);
    splitter->addWidget(m_rightSideWindow);

    m_dockWidget1 = new QDockWidget("Dock 1", this);
    m_rightSideWindow->addDockWidget(Qt::TopDockWidgetArea, m_dockWidget1);
    m_dockWidget1->setTitleBarWidget(new QWidget()); // remove title bar
    m_dockWidget1->setAllowedAreas(Qt::NoDockWidgetArea); // do not allow to dock
    QTextEdit* textEdit1 = new QTextEdit(this); // put any QWidget derived class inside
    m_dockWidget1->setWidget(textEdit1);

    m_dockWidget2 = new QDockWidget("Dock 2", this);
    m_rightSideWindow->addDockWidget(Qt::BottomDockWidgetArea, m_dockWidget2);
    m_dockWidget2->setTitleBarWidget(new QWidget());
    m_dockWidget2->setAllowedAreas(Qt::NoDockWidgetArea);
    QTextEdit* textEdit2 = new QTextEdit(this);
    m_dockWidget2->setWidget(textEdit2);

    m_dockWidget3 = new QDockWidget("Dock 3", this);
    m_rightSideWindow->addDockWidget(Qt::BottomDockWidgetArea, m_dockWidget3);
    QTextEdit* textEdit3 = new QTextEdit(this);
    m_dockWidget3->setWidget(textEdit3);

    setCentralWidget(splitter);

}
MainWindow::~MainWindow()
{
    delete ui;
}
void MainWindow::on_actionRestore_layout_triggered()
{
    QList<QDockWidget*> list = findChildren<QDockWidget*>();
    foreach(QDockWidget* dock, list)
    {
        if(dock->isFloating())
            dock->setFloating(false);
        m_rightSideWindow->removeDockWidget(dock);
        if (dock == m_dockWidget1)
            m_rightSideWindow->addDockWidget(Qt::TopDockWidgetArea, m_dockWidget1);
        else
            m_rightSideWindow->addDockWidget(Qt::BottomDockWidgetArea, dock);
        dock->setVisible(true);
    }
    m_rightSideWindow->splitDockWidget(m_dockWidget2, m_dockWidget3, Qt::Horizontal);
}

enter image description here

Bertrand
  • 279
  • 2
  • 6
  • This is a fantastic answer. Thank thank you for taking the time to write it. One question: what type should `m_rightSideWindow` be declared as (`error: 'm_rightSideWindow' was not declared in this scope`)? – earth Apr 02 '16 at 15:29
  • Nevermind. I figured it out. See my original answer's EDIT section for full details. – earth Apr 02 '16 at 15:45
  • 1
    @orbit Sorry, I have not given the #include file. You did it! :-) – Bertrand Apr 02 '16 at 16:46
  • Thank you. Your answer helps so much. Do you know how I could also keep the functionality shown in the original image (where I can dock it to the full length of the rightmost side) in addition to being able to dock it to half of the bottom widget? I'd like to give users the choice. Right now, I can dock `Dock3` next to `Dock1` or `Dock2`, but I can't dock it to span the entire rightside height of the application. – earth Apr 02 '16 at 16:56
  • 1
    @orbit try to split the main window central area with 2 horizontal QMainWindows. – Bertrand Apr 02 '16 at 19:04