JL Tresset JL Tresset - 2 months ago 25
C++ Question

Force QDockWidget order

We develop a portable application using Qt 5 and I'm currently looking for a way to force the order of multiple QDockWidgets in a dock area. For instance, with two dockable widgets A and B, I would like the following behaviour :


  • A can be either floating or docked on the left

  • B can be either floating or docked on the left BUT at the right of A



Is it possible in any way ? I can't find any reference to such kind of feature.

Answer

Here is a quick sample:

#include <QtCore>
#include <QtGui>
#include <QtWidgets>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QMainWindow mainWindow;
    mainWindow.setCentralWidget(new QLabel("<B>I am a<BR>central widget.</B>"));
    QDockWidget dock1("Dock1");
    dock1.setWidget(new QLabel("Content1"));
    QDockWidget dock2("Dock2");
    dock2.setWidget(new QLabel("Content2"));

    // Valuable lines.
    mainWindow.addDockWidget(Qt::LeftDockWidgetArea, &dock1);
    mainWindow.addDockWidget(Qt::LeftDockWidgetArea, &dock2);
    mainWindow.splitDockWidget(&dock1, &dock2, Qt::Horizontal);

    mainWindow.show();

    return app.exec();
}

Look at Main Window example in Qt Examples And Demos to explore what you can do with docks.

EDIT

#include <QtCore>
#include <QtGui>
#include <QtWidgets>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QMainWindow mainWindow;
    mainWindow.setCentralWidget(new QLabel("<B>I am a<BR>central widget.</B>"));
    QDockWidget dock1("Dock1");
    dock1.setWidget(new QLabel("Content1"));
    QDockWidget dock2("Dock2");
    dock2.setWidget(new QLabel("Content2"));
    dock2.setAllowedAreas(Qt::LeftDockWidgetArea);

    const auto relocateDock1 = [&] (Qt::DockWidgetArea newArea) {
        if (dock1.isFloating())
            return;

        if (newArea == Qt::LeftDockWidgetArea) {
            // Dock is tabified before user drops it. See also
            // QMainWindow::splitDockWidget notes in documentation.
            if (!mainWindow.tabifiedDockWidgets(&dock2).isEmpty())
                mainWindow.addDockWidget(Qt::LeftDockWidgetArea, &dock2);
            mainWindow.splitDockWidget(&dock1, &dock2, Qt::Horizontal);
        }
    };
    const auto relocateDock2 = [&] (bool topLevel) {
        if (topLevel)
            return;

        if (mainWindow.dockWidgetArea(&dock1) == Qt::LeftDockWidgetArea) {
            mainWindow.splitDockWidget(&dock1, &dock2, Qt::Horizontal);
        }
    };
    QObject::connect(&dock1, &QDockWidget::dockLocationChanged, relocateDock1);
    QObject::connect(&dock2, &QDockWidget::topLevelChanged, relocateDock2);

    mainWindow.addDockWidget(Qt::LeftDockWidgetArea, &dock1);
    mainWindow.addDockWidget(Qt::LeftDockWidgetArea, &dock2);
    relocateDock2(false);

    mainWindow.show();

    return app.exec();
}

This way looks ugly and is full of workarounds. But I don't know a way better.

I have spent a lot of time to do it and my advice is to pass up this idea. Maybe it is easier to have a two-column widget in one dock?

Comments