PDA

View Full Version : QMainWindow::restoreGeometry does weird things to floating QDockWidgets?



stryga42
27th August 2021, 19:31
Hi everyone,
I use QMainWindow::restoreGeometry and restoreState, fed with QByteArray's from QSettings to restore the arrangement of QDockWidegt's. It works great when all docks are saved in docked state. If a dock was saved floating and is thus restored floating strange things happen: On the first glance everything looks OK (position and state), but the floating window(s) behave strange:

If you have more than one floating dock their relative stacking is unpredictable and does not follow mouse clicks on the dock title bar (thus window activation or raise commands).
A floating dock may be in front of _any_ other window on the screen. Yes, even in front of other applications. No way to get it into background.
Resizing of the dock does not work. After moving it, resize works. (but not the stacking)

The faulty dockwindows can be healed by docking and undocking them.
Seen on Ubuntu 20.04.3 LTS, GNOME 3.36.8, Qt 5.15. I can reproduce this behavior in a skeleton application, source at the end of this post.

I think that it should work to call restoreGeometry and restoreState before creating the docks and using restoreDockWidget later on - what else would be the use of restoreDockWidget? Still, I turned it around, which means create the docks and call restoreGeometry and restoreState afterwards (and no restoreDockWidget at all). Surprise, surprise, the stacking order is fine, resize is possible! So, problem solved? Well, not completely. The problem is that I have no possibility to find out which docks were restored and which not. Sure, i can call addDockWidget (with some default position) for all docks right after creation. The saved ones will be re-positioned later on. (For example, docks may not be saved because this is the first start of the program or the user added a plugin which creates a hitherto unknown dock.) But I would like to know which docks are "new"... Btw, just omitting addDockWidget is a bad idea - un-saved docks will have no valid layout and are rendered somehow overlapping the central widget.

So my question: Is the strange stacking behavior really a bug or is something wrong with my code?



#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QCoreApplication::setOrganizationName("me");
QCoreApplication::setOrganizationDomain("mydomain.at");
QCoreApplication::setApplicationName("MainWinTest");
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}


#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
protected:
virtual void closeEvent(QCloseEvent *event);
private:
void createDock(QString name);
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H



#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtDebug>
#include <QDockWidget>
#include <QLabel>
#include <QSettings>

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
qInfo()<<"setup MainWindow";
ui->setupUi(this);

qInfo()<<"restore";
QSettings settings;
if(!restoreGeometry(settings.value("layout/geometry").toByteArray()))
qWarning()<<"unable to restore geometry";
if(!restoreState(settings.value("layout/windowState").toByteArray()))
qWarning()<<"unable to restore state";

qInfo()<<"dynamic widgets";
setCentralWidget(new QLabel(QStringLiteral("central"), this));
createDock(QStringLiteral("Dock1"));
createDock(QStringLiteral("Dock2"));
createDock(QStringLiteral("Dock3"));
}

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

void MainWindow::closeEvent(QCloseEvent *event)
{
qInfo()<<"save";
QSettings settings;
settings.setValue("layout/geometry", saveGeometry());
settings.setValue("layout/windowState", saveState());
qInfo()<<"closing MainWindow";
QMainWindow::closeEvent(event);
}

void MainWindow::createDock(QString name)
{
QDockWidget *dock = new QDockWidget(name, this);
dock->setObjectName(name);
dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea | Qt::TopDockWidgetArea);
dock->setStyleSheet("QDockWidget{border: 4px solid #d00000} QDockWidget::title{background: #ffd8c0}");
dock->setWidget(new QLabel(name, dock));
if(restoreDockWidget(dock))
qInfo()<<"restored layout of"<<name;
else
{
qWarning()<<"unable to restore layout of"<<name;
addDockWidget(Qt::RightDockWidgetArea, dock);
}
}


QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
SOURCES += \
main.cpp \
mainwindow.cpp

HEADERS += \
mainwindow.h

FORMS += \
mainwindow.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target



<?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>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>central wid</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>