1

I have been trying to figure out if you could dock a QDockWidget in a QSplitter, here is my original question. However, after doing a lot of digging around, I found this helpful post which lead to another post that stated that QDockWidgets can only be docked on QMainWindows. In the helpful post I linked, there was a comment that led to this solution on the QtCenter.

What I have done, is taken that code and added it to my application. However, I quickly found out that it only works one way. As in if I have a QMainWindow in my QSplitter, I can take the QDockWindow out of the QSplitter and dock it on the main application. However, I cannot re-dock my QSplitter's QDockWindow back into the QSplitter's QMainWindow.

I then tried to create another class called, MyWindow as I figured that maybe I just need to be able to create a seperate QMainWindow class that I can then connect through the GUI and has the same functions as the MainWindowClass. However that too has failed. Here is my code:

MyWindow.hpp

#ifndef MYWINDOW_HPP
#define MYWINDOW_HPP

#include <QMainWindow>
#include <QObject>
#include <QWidget>
#include <QDockWidget>


class MyWindow : public QMainWindow
{
  Q_OBJECT

  public:
    MyWindow(QWidget *child = nullptr);

    QMainWindow* createNewWindow();


  public slots:
    void dragStarted(bool started);
    void enterEvent(QEvent *event);
    void dragEnded() { dw = nullptr; }


  private:
    QDockWidget* dw = nullptr;
};

#endif // MYWINDOW_HPP

MyWindow.cpp

#include "mywindow.hpp"

MyWindow::MyWindow(QWidget *child) : QMainWindow (child){}

QMainWindow* MyWindow::createNewWindow()
{
    QMainWindow *newWindow = new QMainWindow(this);
    newWindow->setWindowFlags(Qt::Widget);
    return newWindow;
}

void MyWindow::dragStarted(bool started)
{
    if(started)
    {
        if(QDockWidget* dock = qobject_cast<QDockWidget*>(sender()))
            dw = dock;
        else
            dw = nullptr;
    }
}

void MyWindow::enterEvent(QEvent *event)
{
    if(dw && dw->parent() != this)
    {
        addDockWidget(Qt::RightDockWidgetArea, dw);
        dw = nullptr;
    }
}

MainWindow.hpp

#ifndef MAINWINDOW_HPP
#define MAINWINDOW_HPP

#include <QMainWindow>
#include <QWidget>
#include <QDockWidget>
#include "mywindow.hpp"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

public slots:
    void dragStarted(bool started);
    void enterEvent(QEvent *event);
    void dragEnded() { dw = nullptr; }

private:
    Ui::MainWindow *ui;
    QDockWidget* dw = nullptr;
};

#endif // MAINWINDOW_HPP

MainWindow.cpp

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

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QWidget *child = nullptr;
    MyWindow myWindow(child);

    QMainWindow *leftWindow = myWindow.createNewWindow();
    QMainWindow *rightWindow = myWindow.createNewWindow();

    leftWindow->addDockWidget(Qt::LeftDockWidgetArea,ui->leftDock);
    rightWindow->addDockWidget(Qt::RightDockWidgetArea,ui->rightDock);

    ui->splitter->addWidget(leftWindow);
    ui->splitter->addWidget(rightWindow);

    //connect(ui->leftDock,SIGNAL(topLevelChanged(bool)),&myWindow,SLOT(dragStarted(bool)));
    //connect(ui->rightDock,SIGNAL(topLevelChanged(bool)),&myWindow,SLOT(dragStarted(bool)));
    connect(ui->leftDock,SIGNAL(topLevelChanged(bool)),this,SLOT(dragStarted(bool)));
    connect(ui->rightDock,SIGNAL(topLevelChanged(bool)),this,SLOT(dragStarted(bool)));

    //connect(ui->leftDock,SIGNAL(dockLocationChanged (Qt::DockWidgetArea)),&myWindow,SLOT(dragEnded()));
    //connect(ui->rightDock,SIGNAL(dockLocationChanged (Qt::DockWidgetArea)),&myWindow,SLOT(dragEnded()));
    connect(ui->leftDock,SIGNAL(dockLocationChanged (Qt::DockWidgetArea)),this,SLOT(dragEnded()));
    connect(ui->rightDock,SIGNAL(dockLocationChanged (Qt::DockWidgetArea)),this,SLOT(dragEnded()));
}

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

void MainWindow::dragStarted(bool started)
{
    if(started)
    {
        if(QDockWidget* dock = qobject_cast<QDockWidget*>(sender()))
            dw = dock;
        else
            dw = nullptr;
    }
}

void MainWindow::enterEvent(QEvent *event)
{
    if(dw && dw->parent() != this)
    {
        addDockWidget(Qt::RightDockWidgetArea, dw);
        dw = nullptr;
    }
}

The commented out pieces of code is what I originally tried to do in order to connect them. My thought process was that MyWindow class should have it's own QDockWidget, however when thinking about it, MainWindow class is the one that actually owns the QDockWidget and I am not really sure if re-assigning the parent QMainWindow is the right way to go or not.

What do I need to do in order to get them to re-dock to their original Parent's QMainWindow?

EDIT:

Here is the ui file should anyone need it:

MainWindow.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>1144</width>
    <height>802</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralWidget">
   <widget class="QSplitter" name="splitter">
    <property name="geometry">
     <rect>
      <x>30</x>
      <y>60</y>
      <width>781</width>
      <height>591</height>
     </rect>
    </property>
    <property name="minimumSize">
     <size>
      <width>681</width>
      <height>551</height>
     </size>
    </property>
    <property name="maximumSize">
     <size>
      <width>16777215</width>
      <height>16777215</height>
     </size>
    </property>
    <property name="frameShape">
     <enum>QFrame::Box</enum>
    </property>
    <property name="frameShadow">
     <enum>QFrame::Raised</enum>
    </property>
    <property name="lineWidth">
     <number>2</number>
    </property>
    <property name="midLineWidth">
     <number>2</number>
    </property>
    <property name="orientation">
     <enum>Qt::Horizontal</enum>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menuBar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>1144</width>
     <height>21</height>
    </rect>
   </property>
  </widget>
  <widget class="QToolBar" name="mainToolBar">
   <attribute name="toolBarArea">
    <enum>TopToolBarArea</enum>
   </attribute>
   <attribute name="toolBarBreak">
    <bool>false</bool>
   </attribute>
  </widget>
  <widget class="QStatusBar" name="statusBar"/>
  <widget class="QDockWidget" name="leftDock">
   <property name="maximumSize">
    <size>
     <width>524287</width>
     <height>300</height>
    </size>
   </property>
   <property name="windowTitle">
    <string>Left Dock</string>
   </property>
   <attribute name="dockWidgetArea">
    <number>1</number>
   </attribute>
   <widget class="QWidget" name="dockWidgetContents">
    <layout class="QGridLayout" name="gridLayout">
     <item row="0" column="0">
      <widget class="QTabWidget" name="tabWidget">
       <widget class="QWidget" name="tab">
        <attribute name="title">
         <string>Tab 1</string>
        </attribute>
       </widget>
       <widget class="QWidget" name="tab_2">
        <attribute name="title">
         <string>Tab 2</string>
        </attribute>
       </widget>
      </widget>
     </item>
    </layout>
   </widget>
  </widget>
  <widget class="QDockWidget" name="rightDock">
   <property name="maximumSize">
    <size>
     <width>524287</width>
     <height>300</height>
    </size>
   </property>
   <property name="windowTitle">
    <string>Right Dock</string>
   </property>
   <attribute name="dockWidgetArea">
    <number>1</number>
   </attribute>
   <widget class="QWidget" name="dockWidgetContents_2">
    <layout class="QGridLayout" name="gridLayout_2">
     <item row="0" column="0">
      <widget class="QTabWidget" name="tabWidget_2">
       <property name="currentIndex">
        <number>0</number>
       </property>
       <widget class="QWidget" name="tab_3">
        <attribute name="title">
         <string>Tab 1</string>
        </attribute>
       </widget>
       <widget class="QWidget" name="tab_4">
        <attribute name="title">
         <string>Tab 2</string>
        </attribute>
       </widget>
      </widget>
     </item>
    </layout>
   </widget>
  </widget>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources/>
 <connections/>
</ui>
Sailanarmo
  • 1,139
  • 15
  • 41
  • You have `#include "ui_mainwindow.h"`, but haven't show the contents of that file. In fact, there seems to be a lot more here than I'd expect for a [mcve], even where you need two subclasses. – Toby Speight Mar 13 '19 at 18:45
  • @TobySpeight, this is correct. I can supply the ui file if needed, I just didn't want to load the question with a bunch of junk. However, in my `MainWindow.cpp` I have labeled two very obvious dock widgets and a splitter. It is probably not the best practice to assume the user will create those themselves. I will link the UI File. – Sailanarmo Mar 13 '19 at 18:47

0 Answers0