0

I'm trying to use dock widgets on the main window class in Qt5. However, when I set the central widget to have a fixed height Qt has trouble docking the windows to the top or bottom. Basically, it looks like there is some "padding" or "margins" above and below the central widget. If I set an auto height on the widget, the docking works fine all they way edge-to-edge (top/bottom). How can I either remove the margins or enable the docking function while using a fixed height central widget?

See screenshots for example.

Dock Right w/ Auto Height (No Margins on Central Widget)

Dock Right w/ Auto Height (No Margins on Central Widget)

Dock Bottom w/ Auto Height (No Margins on Central Widget)

Dock Bottom w/ Auto Height (No Margins on Central Widget)

Dock Bottom w/ Fixed Height (Margins/Padding, won't dock)

Dock Bottom w/ Fixed Height (Margins/Padding--Grey areas, won't dock)

Here is the code if that helps.

Header:

class MainWindow : public QMainWindow {
    Q_OBJECT

public:
    MainWindow(QString);
    ~MainWindow();

private:
    void createDockWindows();
    QListWidget *m_dock_list;
    QString m_directory;
    QWidget *m_mainWidget;
};

Class definition:

MainWindow::MainWindow(QString program)
    : m_directory(".")
{
    m_mainWidget = new QWidget;
    m_mainWidget->setFixedHeight(156);
    m_mainWidget->setStyleSheet("background-color: blue;");

    createDockWindows();

    // set central widget and default size
    setCentralWidget(m_mainWidget);
}

// dock functions
void MainWindow::createDockWindows()
{
    QDockWidget *dock = new QDockWidget(tr("Dock List"), this);
    dock->setAllowedAreas(Qt::LeftDockWidgetArea | 
                          Qt::RightDockWidgetArea |
                          Qt::BottomDockWidgetArea);
    m_dock_list = new QListWidget(dock);
    m_dock_list->addItems(QStringList()
        << "item 1"
        << "item 2"
        << "item 3"
        << "item 4");
    dock->setWidget(m_dock_list);
    addDockWidget(Qt::RightDockWidgetArea, dock);
}
ymoreau
  • 3,402
  • 1
  • 22
  • 60
James
  • 2,488
  • 2
  • 28
  • 45

1 Answers1

0

In case anyone else tries to figure out this behavior, here is what I've found. The top and bottom margins are just Qt trying to place the fixed size widget into a space larger than the widget (obvious). However, the restricted docking ability results from the docking widget having a minimum vertical size. Thus, when window height < central widget height + min(docking widget height) Qt does not allow the dock function. Once the threshold window height is reached (by user resize) then Qt allows the dock function.

I would prefer if the docking feature occurred regardless of window height with an automatic window resize to accommodate the docking window.

Solution using signals

Arguably a bit hacky, and may be hard to maintain if you have a complex layout. But for my use case, this is workable.

  1. Don't enforce the size on the center widget, let it auto-fill the main window.
  2. When the dock changes location it emits the dockLocationChanged. We can auto-size the main window if the dockable window is moved into target location. For my case this is the bottom.

Code:

void MainWindow::createDockWindows()
{
    ...
    QObject::connect(dock, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), 
                     this, SLOT(s_dock_window_resize(Qt::DockWidgetArea)));
}

// Autosize window slot on dock location change.
void MainWindow::s_dock_window_resize(Qt::DockWidgetArea area)
{
    if (area == Qt::DockWidgetArea::BottomDockWidgetArea) {
        // m_mainWidget_min_height is the height we would have enforced
        // on the widget. Now we set it somewhere else and check it here.
        int min_height = m_dock_list->height() + m_mainWidget_min_height;
        if (min_height > MainWindow::height()) {
            MainWindow::resize(MainWindow::width(), min_height);
        }
    }
}
James
  • 2,488
  • 2
  • 28
  • 45