Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. dynamic docks and saveState

dynamic docks and saveState

Scheduled Pinned Locked Moved Unsolved General and Desktop
10 Posts 5 Posters 1.6k Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • P Offline
    P Offline
    Phil K
    wrote on last edited by Phil K
    #1

    I have two types of dock windows in my app: permanent docks which are always created on startup and can only have their visibility toggled by the user, and dynamic docks which can be created and destroyed as needed. When I destroy a dynamic dock, I essentially do the following:

    removeDockWidget(dock);
    dock->setParent(nullptr);
    delete dock;
    

    I assign unique names to all docks so their state and geometry can be saved/restored by the app. All this works fine with one or two quirks. One quirk is that the size o f the byte array saved by the app with saveState is not stable and grows continuously if I delete a dynamic dock and then create a new one to replace it. The new one is guaranteed to have a different object name. It is as if there is some mystery data still existent from the deleted dock. Is there anything else I need to clean up so that saveState only saves the current docks when the app exits?

    Pl45m4P 1 Reply Last reply
    0
    • P Phil K

      I have two types of dock windows in my app: permanent docks which are always created on startup and can only have their visibility toggled by the user, and dynamic docks which can be created and destroyed as needed. When I destroy a dynamic dock, I essentially do the following:

      removeDockWidget(dock);
      dock->setParent(nullptr);
      delete dock;
      

      I assign unique names to all docks so their state and geometry can be saved/restored by the app. All this works fine with one or two quirks. One quirk is that the size o f the byte array saved by the app with saveState is not stable and grows continuously if I delete a dynamic dock and then create a new one to replace it. The new one is guaranteed to have a different object name. It is as if there is some mystery data still existent from the deleted dock. Is there anything else I need to clean up so that saveState only saves the current docks when the app exits?

      Pl45m4P Offline
      Pl45m4P Offline
      Pl45m4
      wrote on last edited by
      #2

      @Phil-K said in dynamic docks and saveState:

      size o f the byte array saved by the app with saveState is not stable and grows continuously

      What byteArray? The setting are stored on the stack, so they are only temporarily available until the window has been restored.

      Are you talking about byteArray as described in this example?
      https://doc.qt.io/qt-5/qmainwindow.html#restoreState


      If debugging is the process of removing software bugs, then programming must be the process of putting them in.

      ~E. W. Dijkstra

      1 Reply Last reply
      0
      • P Offline
        P Offline
        Phil K
        wrote on last edited by Phil K
        #3

        The byte array saved in the QSettings config file when the app closes, as in:

        QSettings settings;
        settings.setValue("windowState", saveState());
        

        The data on that key gets larger and larger when creating and deleting my dynamic docks( inspecting the key after the app exits), even though I thought I was removing the dynamic dock widgets properly, i.e. my concern is the size of the config file itself. I don't want it to expand indefinitely like that.

        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          Hi,

          That's an intriguing issue.

          Can you provide a minimal compilable example that shows that behaviour ?

          Which version of Qt are you using ?

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          1 Reply Last reply
          0
          • P Offline
            P Offline
            Phil K
            wrote on last edited by Phil K
            #5

            @SGaist OK Here's a minimal example below. I am using Qt 5.14.2 on both Linux and Windows.

            Create a c++ widget app with no ui and use the files below. Start the app and use the menu to create a few docks. Close the app with some docks in the window. Inspect the dyndock.ini and note the contents and size. Restart the app. The docks are recreated as expected. Use the menu to delete all docks, then create some new ones. Exit the app and inspect the .ini again. Repeat this cycle a few times and note the state key size in the .ini file. You should see that key growing larger and larger.

            // main.cpp
            #include "mainwindow.h"
            
            #include <QApplication>
            #include <QSettings>
            
            int main(int argc, char *argv[])
            {
                QApplication::setApplicationName("dyndock");
                QApplication::setOrganizationName("test");
                QSettings::setDefaultFormat(QSettings::IniFormat);
            
                QApplication a(argc, argv);
                MainWindow w;
                w.show();
                return a.exec();
            }
            
            // mainwindow.h
            #ifndef MAINWINDOW_H
            #define MAINWINDOW_H
            
            #include <QMainWindow>
            
            class QAction;
            class QMenu;
            class QUuid;
            
            class MainWindow : public QMainWindow
            {
                Q_OBJECT
            public:
                MainWindow(QWidget *parent = nullptr);
                ~MainWindow() override;
            
            private:
                void CreateMenu();
                void RestoreWindows();
                void SaveSettings();
            
            private slots:
                void OnCreateDocks();
                void OnDeleteDocks();
            
            private: // Qt overrides
                void closeEvent(QCloseEvent *event) override;
            
            private:
                QAction *file_create_docks_;
                QAction *file_delete_docks_;
                QMenu *file_menu_;
            };
            #endif // MAINWINDOW_H
            
            // mainwindow.cpp
            #include "mainwindow.h"
            
            #include <QAction>
            #include <QDockWidget>
            #include <QMenuBar>
            #include <QSettings>
            #include <QUuid>
            
            MainWindow::MainWindow(QWidget *parent) :
                QMainWindow(parent),
                file_create_docks_(nullptr),
                file_delete_docks_(nullptr),
                file_menu_(nullptr)
            {
                CreateMenu();
            
                QWidget *central_widget = new QWidget(this);
                central_widget->setMinimumSize(400, 400);
                setCentralWidget(central_widget);
            
                RestoreWindows();
            }
            
            MainWindow::~MainWindow()
            {
            }
            
            void MainWindow::CreateMenu()
            {
                file_create_docks_ = new QAction("Create Dock", this);
                file_delete_docks_ = new QAction("Delete All Docks", this);
                connect(file_create_docks_, &QAction::triggered, this, &MainWindow::OnCreateDocks);
                connect(file_delete_docks_, &QAction::triggered, this, &MainWindow::OnDeleteDocks);
            
                file_menu_ = menuBar()->addMenu("&File");
                file_menu_->addAction(file_create_docks_);
                file_menu_->addAction(file_delete_docks_);
            }
            
            void MainWindow::RestoreWindows()
            {
                QSettings settings;
            
                settings.beginGroup("Docks");
                const int size = settings.beginReadArray("dock");
                for (int i = 0; i < size; ++i) {
                    settings.setArrayIndex(i);
                    const QUuid uuid = settings.value("uuid").toUuid();
                    const QString title = uuid.toString(QUuid::WithoutBraces);
                    QDockWidget *dock = new QDockWidget(title, this);
                    QWidget *dock_widget = new QWidget;
                    dock->setObjectName(title);
                    dock->setWidget(dock_widget);
                    dock->setFeatures(QDockWidget::DockWidgetMovable);
                    dock_widget->setMinimumSize(400, 100);
                    addDockWidget(Qt::RightDockWidgetArea, dock);
                    dock_widget->setFocus();
                }
                settings.endArray();
                settings.endGroup();
            
                settings.beginGroup("Windows");
                restoreGeometry(settings.value("geometry").toByteArray());
                restoreState(settings.value("state").toByteArray());
                settings.endGroup();
            }
            
            void MainWindow::SaveSettings()
            {
                QSettings settings;
                settings.beginGroup("Docks");
                settings.remove("dock");
                settings.beginWriteArray("dock");
                QList<QDockWidget *> docks = findChildren<QDockWidget *>();
                int i = 0;
                for (auto it = docks.begin(); it != docks.end(); ++it) {
                    QDockWidget *dock = *it;
                    settings.setArrayIndex(i);
                    settings.setValue("uuid", dock->objectName());
                    ++i;
                }
                settings.endArray();
                settings.endGroup();
            
                settings.beginGroup("Windows");
                settings.setValue("geometry", saveGeometry());
                settings.setValue("state", saveState());
                settings.endGroup();
            }
            
            void MainWindow::OnCreateDocks()
            {
                // create/add a dock
                const QUuid uuid = QUuid::createUuid();
                const QString title = uuid.toString(QUuid::WithoutBraces);
                QDockWidget *dock = new QDockWidget(title, this);
                QWidget *dock_widget = new QWidget;
                dock->setObjectName(title);
                dock->setWidget(dock_widget);
                dock->setFeatures(QDockWidget::DockWidgetMovable);
                dock_widget->setMinimumSize(400, 100);
                addDockWidget(Qt::RightDockWidgetArea, dock);
            }
            
            void MainWindow::OnDeleteDocks()
            {
                // remove/destroy all docks
                QList<QDockWidget *> docks = findChildren<QDockWidget *>();
                for (auto it = docks.begin(); it != docks.end(); ++it) {
                    QDockWidget *dock = *it;
                    removeDockWidget(dock);
                    dock->setParent(nullptr);
                    delete dock;
                    dock = nullptr;
                }
            }
            
            void MainWindow::closeEvent(QCloseEvent *event)
            {
                Q_UNUSED(event)
                SaveSettings();
            }
            
            1 Reply Last reply
            0
            • Chris KawaC Offline
              Chris KawaC Offline
              Chris Kawa
              Lifetime Qt Champion
              wrote on last edited by
              #6

              I've encountered this as well some time ago. I didn't go very deep into the QMainWindow code, but it seems it basically never discards information about the removed docks. My guess is this is supposed to be a feature not a bug. If you delete a dock and later recreate it with the same name you can restore it the way it was before.

              This of course works for a constant set of docks that don't change, but yeah, also leads to the problem you described if you have many unique names. In my case this led to extreme settings file bloat and after couple weeks of using the app users experienced worsening slowdowns on settings load/save. There were thousands of entries in the settings file even though only a few actual docks.

              The way we dealt with it was to create a pool of names/ids that would only grow when there were more docks than slots in the pool (named e.g. "dock_0" to "dock_xx"). We would then keep track of the free and occupied slots in the pool and reuse them as they come and go. Later on we added a grouping feature that would kinda tag certain docks to let them reuse ids only from the same group as theirs. This had a nice additional property of similar docks appearing in the same spot in the app instead of always recreated in some default place (which previously annoyed a lot of people). All in all this let us keep number of entries in the settings at pretty much constant maximum level limited to a fixed number of docks we allowed to be shown at the same time.

              From implementation point of view we've inherited from QDockWidget and in its constructor it picked an id from the free pool and then in destructor returned it to that pool. We also kept track which docks were opened at the time of saving state so that at the time of loading they would be given the same ids they had in previous session and thus were restored in the same place.

              P 1 Reply Last reply
              1
              • Chris KawaC Chris Kawa

                I've encountered this as well some time ago. I didn't go very deep into the QMainWindow code, but it seems it basically never discards information about the removed docks. My guess is this is supposed to be a feature not a bug. If you delete a dock and later recreate it with the same name you can restore it the way it was before.

                This of course works for a constant set of docks that don't change, but yeah, also leads to the problem you described if you have many unique names. In my case this led to extreme settings file bloat and after couple weeks of using the app users experienced worsening slowdowns on settings load/save. There were thousands of entries in the settings file even though only a few actual docks.

                The way we dealt with it was to create a pool of names/ids that would only grow when there were more docks than slots in the pool (named e.g. "dock_0" to "dock_xx"). We would then keep track of the free and occupied slots in the pool and reuse them as they come and go. Later on we added a grouping feature that would kinda tag certain docks to let them reuse ids only from the same group as theirs. This had a nice additional property of similar docks appearing in the same spot in the app instead of always recreated in some default place (which previously annoyed a lot of people). All in all this let us keep number of entries in the settings at pretty much constant maximum level limited to a fixed number of docks we allowed to be shown at the same time.

                From implementation point of view we've inherited from QDockWidget and in its constructor it picked an id from the free pool and then in destructor returned it to that pool. We also kept track which docks were opened at the time of saving state so that at the time of loading they would be given the same ids they had in previous session and thus were restored in the same place.

                P Offline
                P Offline
                Phil K
                wrote on last edited by
                #7

                @Chris-Kawa OK, based on what you've described, I'm going to alter my design so that it uses a fixed size pool of available docks instead of using dynamic object naming with uuids. Not gonna fight this one since I have so many other battles to wage.

                Might be worth amending the Qt docs to clarify the hazard, i.e. removeDockWidget does not remove all window state related to that dock.

                Thanks for your input.

                1 Reply Last reply
                0
                • SGaistS Offline
                  SGaistS Offline
                  SGaist
                  Lifetime Qt Champion
                  wrote on last edited by
                  #8

                  You should check the bug report system to see if there's something related. If not please open a ticket to suggest that edition. Provide your example as well so if it's considered a bug the debugging can start faster.

                  Interested in AI ? www.idiap.ch
                  Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                  P 1 Reply Last reply
                  0
                  • SGaistS SGaist

                    You should check the bug report system to see if there's something related. If not please open a ticket to suggest that edition. Provide your example as well so if it's considered a bug the debugging can start faster.

                    P Offline
                    P Offline
                    Phil K
                    wrote on last edited by
                    #9

                    @SGaist Will do.

                    J 1 Reply Last reply
                    0
                    • P Phil K

                      @SGaist Will do.

                      J Offline
                      J Offline
                      julyighor
                      wrote on last edited by
                      #10

                      @Phil-K Hi, did you find any solution?

                      1 Reply Last reply
                      0

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved