1

QDockWidget has a feature where you can double click on the title bar and the dock will toggle to a floating window and back to its docked state. The problem is if you move and resize the floating window and then toggle back to the dock and then back to floating again, your position and size are lost.

I've looked for solutions to resize and move a QDockWidget and I've taken a look at the Qt source code for QDockWidget. I've created a small subclass of QDockWidget that appears to solve the problem. It overrides the mouseDoubleClick, resize and move events, filtering out the unwanted "random" resizing and positioning by Qt and stores the information about screen, position and size in a struct that I store in QSettings for persistence between sessions.

// header
#include <QDockWidget>
#include "global.h"
class DockWidget : public QDockWidget
{
    Q_OBJECT
public:
    DockWidget(const QString &title, QWidget *parent = nullptr);
    QSize sizeHint() const;
    void rpt(QString s);
    struct DWLoc {
        int screen;
        QPoint pos;
        QSize size;
    };
    DWLoc dw;
    bool ignore;
protected:
    bool event(QEvent *event);
    void resizeEvent(QResizeEvent *event);
    void moveEvent(QMoveEvent *event);
};


// cpp
#include "dockwidget.h"

DockWidget::DockWidget(const QString &title, QWidget *parent)
    : QDockWidget(title, parent)
{
    ignore = false;
}

bool DockWidget::event(QEvent *event)
{
    if (event->type() == QEvent::MouseButtonDblClick) {
        ignore = true;
        setFloating(!isFloating());
        if (isFloating()) {
            // move and size to previous state
            QRect screenres = QApplication::desktop()->screenGeometry(dw.screen);
            move(QPoint(screenres.x() + dw.pos.x(), screenres.y() + dw.pos.y()));
            ignore = false;
            adjustSize();
        }
        ignore = false;
        return true;
    }
    QDockWidget::event(event);
    return true;
}

void DockWidget::resizeEvent(QResizeEvent *event)
{
    if (ignore) {
        return;
    }
    if (isFloating()) {
        dw.screen = QApplication::desktop()->screenNumber(this);
        QRect r = geometry();
        QRect a = QApplication::desktop()->screen(dw.screen)->geometry();
        dw.pos = QPoint(r.x() - a.x(), r.y() - a.y());
        dw.size = event->size();
    }
}

QSize DockWidget::sizeHint() const
{
    return dw.size;
}

void DockWidget::moveEvent(QMoveEvent *event)
{
    if (ignore || !isFloating()) return;
    dw.screen = QApplication::desktop()->screenNumber(this);
    QRect r = geometry();
    QRect a = QApplication::desktop()->screen(dw.screen)->geometry();
    dw.pos = QPoint(r.x() - a.x(), r.y() - a.y());
    dw.size = QSize(r.width(), r.height());
}

While this appears to be working is there a simpler way to accomplish this? What do I do if a QDockWidget was on a screen that is now turned off?

Rory
  • 113
  • 8
  • Since I have a similar problem, did you stick with this or find a way to just call `QDockWidget::setWorkMagically(true)` ? – namezero Oct 13 '19 at 11:59
  • No, I moved on to other things. – Rory Nov 08 '19 at 23:20
  • Ok, thanks for the update.I solved this by saving it with the main window geometry and embedding the actual widget inside the mainwindow owned one. – namezero Nov 10 '19 at 06:57

0 Answers0