Unable to restore floating QToolBar via QSettings



  • I've tried a number of different approaches, and feel like there should be something simpler that I'm missing. I've searched the forums, but to no avail.

    If you run the following (and any of the three attempts to correct the issue), load the program up, have the second toolbar be positioned and floating, switch to "View 1" (which doesn't need toolbar 2, so it should be removed), close the program and restart. The toolbar 2 (if visible) is in the wrong spot. It works fine for dock widgets.

    Any suggestions? Thoughts?

    // qt includes
    #include <QtWidgets\QMainWindow>
    #include <QtWidgets\QApplication>
    #include <QtWidgets\QToolBar>
    #include <QtWidgets\QDockWidget>
    #include <QtCore\QSettings>
    
    class MyMainWindow : public QMainWindow
    {
    public:
    	MyMainWindow(QWidget* parent = nullptr) : QMainWindow(parent)
    	{
    		// setup main window
    		setCentralWidget(new QWidget(this));
    
    		// toolbar 1 setup
    		toolbar1 = new QToolBar("Toolbar 1");
    		toolbar1->setObjectName("Toolbar 1");
    		addToolBar(Qt::TopToolBarArea, toolbar1);
    		for ( int i = 0; i < 3; i++ )
    			toolbar1->addAction("TB1_" + QString::number(i), []() {});
    
    		// toolbar 2
    		toolbar2 = new QToolBar("Toolbar 2");
    		toolbar2->setObjectName("Toolbar 2");
    		addToolBar(Qt::TopToolBarArea, toolbar2);
    		for ( int i = 0; i < 5; i++ )
    			toolbar2->addAction("TB2_" + QString::number(i), []() {});
    
    		// dock examples
    		dock1 = new QDockWidget("Dock 1", this);
    		dock1->setObjectName("Dock 1");
    		addDockWidget(Qt::LeftDockWidgetArea, dock1);
    		dock2 = new QDockWidget("Dock 2", this);
    		dock2->setObjectName("Dock 2");
    		addDockWidget(Qt::LeftDockWidgetArea, dock2);
    
    		// *** CRUX OF ISSUES *** //
    		// setup toolbar 1 calls
    		toolbar1->addAction("View 1", [this]()
    		{
    			// attempt 1 - use remove/custom 'restore'? bad placement
    			//removeToolBar(toolbar2); // unsure what to pair this with
    
    			// attempt 2 - use QSettings?
    			//// save current location of toolbar
    			//QSettings settings;
    			//settings.setValue(toolbar2->objectName(), toolbar2->saveGeometry()); // not right - does top-level/all widgets
    			//toolbar2->setHidden(true); // doesn't work for the context menu (even if custom)
    
    			// attempt 3 - custom use of QSettings? very buggy...
    			QSettings settings;
    			settings.setValue(toolbar2->objectName() + "_floating", toolbar2->isFloating());
    			settings.setValue(toolbar2->objectName() + "_geometry", toolbar2->geometry());
    			settings.setValue(toolbar2->objectName() + "_visible", toolbar2->isVisible());
    			settings.setValue(toolbar2->objectName() + "_toolbararea", (unsigned)this->toolBarArea(toolbar2));
    			removeToolBar(toolbar2);
    
    			// dock example - works fine!
    			removeDockWidget(dock2);
    		});
    		QAction* defaultView = toolbar1->addAction("View 2", [this]()
    		{
    			// attempt 1 - use remove/custom 'restore'? bad placement
    			//addToolBar(toolbar2);
    			//toolbar2->show(); // has bad placement
    
    			// attempt 2 - use QSettings?
    			//// restore location of toolbar
    			//QSettings settings;
    			//toolbar2->restoreGeometry(settings.value(toolbar2->objectName()).toByteArray()); // not right - does top-level/all widgets
    			//toolbar2->setHidden(false); // doesn't work for the context menu (even if custom)
    
    			// attempt 3 - custom use of QSettings? very buggy...
    			QSettings settings;
    			Qt::ToolBarArea area = ( Qt::ToolBarArea )settings.value(toolbar2->objectName() + "_toolbararea").toUInt();
    			addToolBar(area, toolbar2); // not right - may re-order toolbars
    			toolbar2->setVisible(settings.value(toolbar2->objectName() + "_visible").toBool());
    			bool isFloating = settings.value(toolbar2->objectName() + "_floating").toBool();
    			if ( isFloating )
    				toolbar2->setWindowFlags(toolbar2->windowFlags() | Qt::FramelessWindowHint);
    			toolbar2->setGeometry(settings.value(toolbar2->objectName() + "_geometry").toRect());
    
    			// dock example - works fine!
    			restoreDockWidget(dock2);
    		});
    		// *** END CRUX OF ISSUES *** //
    
    		QAction* quitAction = toolbar1->addAction("Quit", [this]() { this->close(); });
    		quitAction->setShortcut(Qt::Key_Q);
    
    		resize(1200, 800);
    
    		// its all setup - restore prior state
    		LoadUI();
    
    		// load default view
    		defaultView->trigger();
    	}
    
    	void LoadUI()
    	{
    		// load settings from registry
    		QSettings settings;
    		QString sQState = "windowState";
    		bool hasSettings = settings.contains(sQState);
    		if ( hasSettings )
    			restoreState(settings.value(sQState).toByteArray());
    		QString sQGeometry = "windowGeometry";
    		hasSettings = settings.contains(sQGeometry);
    		if ( hasSettings )
    			restoreGeometry(settings.value(sQGeometry).toByteArray());
    	}
    
    	void closeEvent(QCloseEvent* event)
    	{
    		QSettings settings;
    		QString sQState = "windowState";
    		settings.setValue(sQState, saveState());
    		QString sQGeometry = "windowGeometry";
    		settings.setValue(sQGeometry, saveGeometry());
    	}
    
    private:
    	QToolBar *toolbar1, *toolbar2;
    	QDockWidget *dock1, *dock2;
    };
    
    int main( int argc, char *argv[] )
    {
    	// setup application
    	QApplication app( argc, argv );
    	app.setOrganizationName("QtExample");
    	app.setApplicationName("ToolBarSettingsBug");
    
    	// setup main window
    	MyMainWindow mainWin;
    
    	mainWin.show();
    	return app.exec();
    }
    

  • Qt Champions 2016

    I'd suggest something along those lines:

    MyMainWindow::MyMainWindow(QWidget * parent = Q_NULLPTR)
        : QMainWindow(parent);
    {
        // ...
        toolbar1->addAction("View 1", [this]()  {
            restoreView("View1");
        });
        toolbar1->addAction("View 2", [this]()  {
            restoreView("View2");
        });
        // ...
    }
    
    void MyMainWindow::restoreView(const QString & name)
    {
        currentView = name; //< currentView is a QString and is only to keep track of the currently shown view
        QString key = QStringLiteral("%1/State").arg(name);
    
        QSettings settings;
        if (settings.contains(key))
            restoreState(settings.value(key).toByteArray());
    }
    
    void MyMainWindow::closeEvent(QCloseEvent * event)
    {
        QString key = QStringLiteral("%1/State").arg(currentView);
    
        QSettings settings;
        settings.setValue(key, saveState());
        // Save the geometry ...
    
        QMainWindow::closeEvent(event);
    }
    

    PS:
    And people mock me for my aversion to lambdas ... go figure ...



  • Thanks @kshegunov for the suggestion. I understand where you're going with that, unfortunately I believe eg. if you resize the window on one view, it will restore the old window size when you switch views. ie. that more customized QSettings logic would be needed.

    Any other ideas?

    Anyone know why there isn't a restoreToolBar(...) function akin to restoreDockWidget(...)?


    Edit Addition: Though I notice you're only saving/restoring the state (so the window size is a bad example), it does mean the geometry will be inconsistent between views...


  • Qt Champions 2016

    @Erika said in Unable to restore floating QToolBar via QSettings:

    it does mean the geometry will be inconsistent between views...

    Inconsistent how? If you need the geometry to be tied to the view, then you just need to add a couple of lines to save/restore it, but I'd think this is a bad idea.

    Anyone know why there isn't a restoreToolBar(...) function akin to restoreDockWidget(...)?

    Probably because toolbars don't have a real state as the dock widgets. They're tied to a side of the window and nothing more, they don't have their own independent geometry, but depend on the geometry of the main window, and they aren't floating around as far as I remember.

    Seems I err. It's been some time since I've worked with GUIs.



  • Thanks @kshegunov for the response. We've decided to directly use a combination of setVisible/setHidden instead of removeToolBar, and manually track floating visibility of toolbars for re-loading the ui.

    I've also logged a bug: https://bugreports.qt.io/browse/QTBUG-58095 to address floating, hidden toolbars not being able to readily restore state unlike their dock widget counterparts.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.