PDA

View Full Version : Floating QDockWidget not re-docked by QMainWindow::restoreState



stefanadelbert
2nd March 2010, 07:48
I'm having poblems with QMainWindow::saveState when QDockWidgets are nested or tabbed. If I float one of the nested/tabbed QDockWidgets and then call QMainWindow::restoreState, the floating QDockWidget state is not restored and it is left floating.

So these are the steps:

Call QMainWindow::saveState on a main window with two docked QDockWidgets which are nested/tabbed
Float one of the nested/tabbed QDockWidgets, i.e. one is docked and the other is floating
Call QMainWindow::restoreState


EXPECT: Both QDockWidgets to be nested/tabbed as they were when QMainWindow::saveState was called.
ACTUAL: The nested/tabbed state of the QDockWidget is not restored - it's left floating.

Has anyone noticed this behaviour before?

stefanadelbert
2nd March 2010, 08:19
I put together some simple example code (using the Dock Widgets example) to demonstrate the problem and found that I was getting even less of the behaviour that I expected!

This code creates a QMainWindow with two QDockWidgets. There is a File menu with "Save State" and Restore State" options which call saveState and restoreState respectively.

If I save the state of the QMainWindow with the widgets both docked on the left side, then float both of them, then restore the state, both QDockWidgets are left floating. I would expect them to be restored to their docked state. Is this wrong?


#include <QListWidget>
#include <QMenu>

#include <QtGui/QMainWindow>
#include "ui_testrestoredock.h"

class TestRestoreDock : public QMainWindow
{
Q_OBJECT

public:
TestRestoreDock(QWidget *parent = 0, Qt::WFlags flags = 0);
~TestRestoreDock();

private:
Ui::TestRestoreDockClass ui;

private slots:
void SaveState();
void RestoreState();

private:
QListWidget* customerList;
QListWidget* paragraphsList;

QMenu* fileMenu;

QAction* saveStateAction;
QAction* restoreStateAction;
};


#include <QDockWidget>
#include <QSettings>

#include "testrestoredock.h"

TestRestoreDock::TestRestoreDock(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);

saveStateAction = new QAction(tr("&Save State"), this);
connect(saveStateAction, SIGNAL(triggered()), this, SLOT(SaveState()));

restoreStateAction = new QAction(tr("&Restore State"), this);
connect(restoreStateAction, SIGNAL(triggered()), this, SLOT(RestoreState()));

fileMenu = menuBar()->addMenu(tr("&File"));
fileMenu->addAction(saveStateAction);
fileMenu->addAction(restoreStateAction);

QDockWidget *dock = new QDockWidget(tr("Customers"), this);
dock->setAllowedAreas(Qt::AllDockWidgetAreas);
customerList = new QListWidget(dock);
customerList->addItems(QStringList()
<< "John Doe, Harmony Enterprises, 12 Lakeside, Ambleton"
<< "Jane Doe, Memorabilia, 23 Watersedge, Beaton"
<< "Tammy Shea, Tiblanka, 38 Sea Views, Carlton"
<< "Tim Sheen, Caraba Gifts, 48 Ocean Way, Deal"
<< "Sol Harvey, Chicos Coffee, 53 New Springs, Eccleston"
<< "Sally Hobart, Tiroli Tea, 67 Long River, Fedula");
dock->setWidget(customerList);
addDockWidget(Qt::LeftDockWidgetArea, dock);

dock = new QDockWidget(tr("Paragraphs"), this);
paragraphsList = new QListWidget(dock);
paragraphsList->addItems(QStringList()
<< "Thank you for your payment which we have received today."
<< "Your order has been dispatched and should be with you "
"within 28 days."
<< "We have dispatched those items that were in stock. The "
"rest of your order will be dispatched once all the "
"remaining items have arrived at our warehouse. No "
"additional shipping charges will be made."
<< "You made a small overpayment (less than $5) which we "
"will keep on account for you, or return at your request."
<< "You made a small underpayment (less than $1), but we have "
"sent your order anyway. We'll add this underpayment to "
"your next bill."
<< "Unfortunately you did not send enough money. Please remit "
"an additional $. Your order will be dispatched as soon as "
"the complete amount has been received."
<< "You made an overpayment (more than $5). Do you wish to "
"buy more items, or should we return the excess to you?");
dock->setWidget(paragraphsList);
addDockWidget(Qt::LeftDockWidgetArea, dock);
}

TestRestoreDock::~TestRestoreDock()
{}

void TestRestoreDock::SaveState()
{
QSettings settings("Test", "Test Dock Problem");
settings.setValue("MainWindow/State", saveState());
settings.setValue("MainWindow/Geometry", saveGeometry());
}

void TestRestoreDock::RestoreState()
{
QSettings settings("Test", "Test Dock Problem");
restoreState(settings.value("MainWindow/State").toByteArray());
restoreGeometry(settings.value("MainWindow/Geometry").toByteArray());
}


#include "testrestoredock.h"
#include <QtGui/QApplication>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TestRestoreDock w;
w.show();
return a.exec();
}

mrvk
2nd March 2010, 13:20
For restoreState and saveState to work properly, we need to ensure that the objectname of each saved object is unique.

Ensure that the objectname of both the dock widgets are different.

eg. dock->setObjectName("Customers");

and the second one can be

dock->setObjectName("Paragraphs");

Hope it helps.

stefanadelbert
2nd March 2010, 22:30
Indeed, that makes a big difference. That now gets me to the point where I can actually demonstrate the problem that I'm having! I've made the relevant changes to the code and pasted it in below.

So, back to my original problem:


Call QMainWindow::saveState on a main window with two docked QDockWidgets which are nested/tabbed
Float one of the nested/tabbed QDockWidgets, i.e. one will be docked and the other floating
Call QMainWindow::restoreState


EXPECT: Both QDockWidgets to be nested/tabbed as they were when QMainWindow::saveState was called.
ACTUAL: The nested/tabbed state of the QDockWidget is not restored - it's left floating.

BTW: I've added the code to set the obecjetName for each dock below. I've also changed to setGeometry/restoreGeometry code - I'm on Win7 and the restore geometry doesn't work nicely for windows in the maximised state.



#include <QListWidget>
#include <QMenu>

#include <QtGui/QMainWindow>
#include "ui_testrestoredock.h"

class TestRestoreDock : public QMainWindow
{
Q_OBJECT

public:
TestRestoreDock(QWidget *parent = 0, Qt::WFlags flags = 0);
~TestRestoreDock();

private:
Ui::TestRestoreDockClass ui;

private slots:
void SaveState();
void RestoreState();

private:
QListWidget* customerList;
QListWidget* paragraphsList;

QMenu* fileMenu;

QAction* saveStateAction;
QAction* restoreStateAction;
};


#include <QDockWidget>
#include <QSettings>

#include "testrestoredock.h"

TestRestoreDock::TestRestoreDock(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);

saveStateAction = new QAction(tr("&Save State"), this);
connect(saveStateAction, SIGNAL(triggered()), this, SLOT(SaveState()));

restoreStateAction = new QAction(tr("&Restore State"), this);
connect(restoreStateAction, SIGNAL(triggered()), this, SLOT(RestoreState()));

fileMenu = menuBar()->addMenu(tr("&File"));
fileMenu->addAction(saveStateAction);
fileMenu->addAction(restoreStateAction);

QDockWidget *dock = new QDockWidget(tr("Customers"), this);
dock->setObjectName(tr("Customers"));
dock->setAllowedAreas(Qt::AllDockWidgetAreas);
customerList = new QListWidget(dock);
customerList->addItems(QStringList()
<< "John Doe, Harmony Enterprises, 12 Lakeside, Ambleton"
<< "Jane Doe, Memorabilia, 23 Watersedge, Beaton"
<< "Tammy Shea, Tiblanka, 38 Sea Views, Carlton"
<< "Tim Sheen, Caraba Gifts, 48 Ocean Way, Deal"
<< "Sol Harvey, Chicos Coffee, 53 New Springs, Eccleston"
<< "Sally Hobart, Tiroli Tea, 67 Long River, Fedula");
dock->setWidget(customerList);
addDockWidget(Qt::LeftDockWidgetArea, dock);

dock = new QDockWidget(tr("Paragraphs"), this);
dock->setObjectName(tr("Paragraphs"));
paragraphsList = new QListWidget(dock);
paragraphsList->addItems(QStringList()
<< "Thank you for your payment which we have received today."
<< "Your order has been dispatched and should be with you "
"within 28 days."
<< "We have dispatched those items that were in stock. The "
"rest of your order will be dispatched once all the "
"remaining items have arrived at our warehouse. No "
"additional shipping charges will be made."
<< "You made a small overpayment (less than $5) which we "
"will keep on account for you, or return at your request."
<< "You made a small underpayment (less than $1), but we have "
"sent your order anyway. We'll add this underpayment to "
"your next bill."
<< "Unfortunately you did not send enough money. Please remit "
"an additional $. Your order will be dispatched as soon as "
"the complete amount has been received."
<< "You made an overpayment (more than $5). Do you wish to "
"buy more items, or should we return the excess to you?");
dock->setWidget(paragraphsList);
addDockWidget(Qt::LeftDockWidgetArea, dock);
}

TestRestoreDock::~TestRestoreDock()
{}

void TestRestoreDock::SaveState()
{
QSettings settings("Test", "Test Dock Problem");
settings.setValue("MainWindow/State", saveState());
settings.setValue("MainWindow/Geometry", geometry());
}

void TestRestoreDock::RestoreState()
{
QSettings settings("Test", "Test Dock Problem");
restoreState(settings.value("MainWindow/State").toByteArray());
setGeometry(settings.value("MainWindow/Geometry").toRect());
show();
}


#include "testrestoredock.h"
#include <QtGui/QApplication>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TestRestoreDock w;
w.show();
return a.exec();
}

norobro
3rd March 2010, 03:23
I used the dockwidget example from Qt, added save settings & restore settings QActions to the File menu, copied your code for the slots, connected them and it worked like a charm.
Are your slots being called? Stick the following statement at the end of your SaveState slot to see if there are any problems:
qDebug()<< settings.status()
Other than the fact that I'm on Linux:cool:, I got nothing.

stefanadelbert
3rd March 2010, 03:39
I wish I could be doing this on Linux!

I'm seeing some weirdness which I'm attributing to Win7 windows management:


I've also changed to geometry()/restoreGeometry() - I'm on Win7 and the restore geometry doesn't work nicely for windows in the maximised state.

I suppose that it's possible that this is a platform specific problem, but I would be surprised if it is. I reckon it's something that I'm doing wrong.

I'll see if I can get something useful using qDebug and post back.

Thanks for the response.

stefanadelbert
3rd March 2010, 04:37
OK, I've done what you did. I took the dockwidgets example that comes with Qt 4.6.0 and I added the following:
State menu with Save and Restore actions
Save and Restore slots
Connections for Save and Restore actions to Save and Restore slots
setObjectName for both docks to ensure unique names


I then do the following:

Stack one dock on top of the other so that they are tabbed
Save state
Float one of the docks
Restore state


I would expect the floated dock to be restored to its tabbed state with with the other dock as it was when the state was saved. However it is left floating.

I've attached the source files for the modified dockwidgets example.

norobro
3rd March 2010, 05:03
As I've stated before on here, I need to work on my reading comprehension. I completely missed the fact that you said that you stacked the docks. Neither your code nor my code produce what I, too, consider the expected results.

I'll keep pluggin'.

stefanadelbert
3rd March 2010, 21:26
It feels like it might be time to call this a bug. Or maybe it's a feature, but it doesn't seem likely.

What's the next step with this? Who do I report it to?

norobro
3rd March 2010, 22:24
Looks like a bug to me too. But what do we know? Here (http://qt.nokia.com/doc/4.6/bughowto.html) is the info in the docs for the latest Qt version.

One thing I did notice is (using your scenario):

Call QMainWindow::saveState on a main window with two docked QDockWidgets which are nested/tabbed
Float one of the nested/tabbed QDockWidgets, i.e. one will be docked and the other floating
Call QMainWindow::restoreState - doesn't work.

If you then click the float button (or double click on the top bar) the floating widget will return to tabbed mode. So the app is retaining the information about the previous location of the floated tab. Apparently "saveState()" doesn't return that information to "QSettings.setValue".

I've never filed a bug report either. I'd appreciate it if you'd post back about what happens.

stefanadelbert
4th March 2010, 00:03
I get the same behaviour on my side when double clicking the QDockWidget titlebar.

I'll go one step further though and say that it's not the previous state that is being "remembered" by the application. I think the application has the correct state stored for the QDockWidget, but it just isn't applying the "float" property correctly. I suspect this because I'm building an app that has a layout manager allowing the user to save an arbitrary number of layouts (or QMainWindow states) and then restore them from a list in the menu. When switching back to a layout that has tabbed QDockWidgets, the floating ones aren't restored (a la this bug), but double clicking their title bars does restore them correctly. So the app knows where they should be placed (i.e. QMainWindow state was actually restored correctly), but maybe just doesn't call QDockWidget::setFloating correctly.

stefanadelbert
4th March 2010, 02:58
Bug already logged (http://bugreports.qt.nokia.com/browse/QTBUG-7921 (QTBUG-7921)). Would be great if some of you could vote for it to get fixed!

zulis
3rd April 2013, 12:03
Floating dock widget problem still exists in Qt 5.0.1 I found a workaround. After state restore do this:

if(yourDockWidget->isFloating())
{
yourDockWidget->setFloating(true);
}And widget becomes dock able again.

achronop
11th September 2014, 13:26
Thank you for the useful post

Dariusz
20th October 2016, 21:16
Not sure if it matter but in QT 5.5 and python 3.5 from my tests they all work fine when restoring/storing of QDockWidget.