Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Saving QTableView state
Qt 6.12 LTS is out! See what's new in the release blog

Saving QTableView state

Scheduled Pinned Locked Moved Solved General and Desktop
12 Posts 4 Posters 2.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.
  • PerdrixP Offline
    PerdrixP Offline
    Perdrix
    wrote on last edited by Perdrix
    #1

    If a user has moved/resized the table columns, I want to save that when the table view is closed

    1. Is that accomplished with e.g.

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

    for the table view?

    1. Is it possible to do this without sub-classing QTableView to add a closeEvent handler? Can I do this in the owning widget's closeEvent() or has the TableView gone at that point?

    Thanks
    David

    JonBJ 1 Reply Last reply
    0
    • PerdrixP Offline
      PerdrixP Offline
      Perdrix
      wrote on last edited by Perdrix
      #10

      The final code to save the state of the Horizontal header in the QMainWindow::closeEvent handler reads like this:

      QSettings settings;
      settings.setValue("geometry", saveGeometry());
      settings.setValue("windowState", saveState());
      QTableView* tableView = this->findChild<QTableView*>("tableView");
      settings.setValue("Dialogs/StackingDlg/TableView/HorizontalHeader/windowState",
      	tableView->horizontalHeader()->saveState());
      

      it relies on the tableView object being named but that is normally true.
      David

      JonBJ 1 Reply Last reply
      1
      • PerdrixP Perdrix

        If a user has moved/resized the table columns, I want to save that when the table view is closed

        1. Is that accomplished with e.g.

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

        for the table view?

        1. Is it possible to do this without sub-classing QTableView to add a closeEvent handler? Can I do this in the owning widget's closeEvent() or has the TableView gone at that point?

        Thanks
        David

        JonBJ Offline
        JonBJ Offline
        JonB
        wrote on last edited by JonB
        #2

        @Perdrix
        What do you think your saveState() is a member of? Your QTableView?? It is a method in QMainWindow:

        Saves the current state of this mainwindow's toolbars and dockwidgets. This includes the corner settings which can be set with setCorner().

        There is QWidget::saveGeometry(), but:

        Saves the current geometry and state for top-level widgets.

        Your QTableView perhaps is not a "top-level" widget, and I think this would only save geometry, nothing about any columns.

        Ah, I see there is a QHeaderView::saveState(). I would assume this is what you want.

        Yes you should be able to call this from, say, "the owning widget's closeEvent() ". That is delivered before the widget is closed, upon a request to close, because you can e.g. choose to ignore the event and the widget will not close. The example at https://doc.qt.io/qt-6/qtwidgets-mainwindows-application-example.html#close-event-handler is often used as the place to save settings.

        1 Reply Last reply
        0
        • PerdrixP Offline
          PerdrixP Offline
          Perdrix
          wrote on last edited by Perdrix
          #3

          I sub-classed QTableView:

          #include <QTableView>
          
          class QCloseEvent;
          class QContextMenuEvent;
          
          namespace DSS
          {
              class TableView :
                  public QTableView
              {
                  typedef QTableView
                      Inherited;
          
                  Q_OBJECT
          
              public:
                  explicit TableView(QWidget* parent = nullptr);
          
                  ~TableView() noexcept
                  {
                  }
          
              protected:
                  void closeEvent([[maybe_unused]] QCloseEvent* e) override;
          
                  void contextMenuEvent([[maybe_unused]] QContextMenuEvent* event) override;
              };
          }
          

          and in the cpp file:

          TableView::TableView(QWidget* parent) :
          	QTableView{ parent }
          {
          	QSettings settings;
          	horizontalHeader()->restoreState(
          		settings.value("Dialogs/StackingDlg/TableView/HorizontalHeader/windowState").toByteArray());
          }
          
          void TableView::closeEvent([[maybe_unused]] QCloseEvent* e)
          {
          	QSettings settings;
          	settings.setValue("Dialogs/StackingDlg/TableView/HorizontalHeader/windowState", 
          		horizontalHeader()->saveState());
          }
          
          void TableView::contextMenuEvent([[maybe_unused]] QContextMenuEvent* e)
          {
          	QMenu menu(this);
          
          	menu.exec(e->globalPos());
          }
          

          But the closeEvent mf was not called (placed a breakpoint in there)??? (The ctor was invoked)

          What am I doing wrong?

          Thanks
          David

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

            Hi,

            Your error is to assume that all widgets get a close event. That's not the case. It's the case for the top level widget but not for its children.

            Also, the saving and loading of setting should rather be handled by the widget that manages it.

            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
            1
            • PerdrixP Offline
              PerdrixP Offline
              Perdrix
              wrote on last edited by Perdrix
              #5

              So does that mean only the QMainWindow gets a closeEvent, or that if the TableView is a child of a Widget called StackingDlg, that it will get a closeEvent() ?

              In this case the StackingDlg is someway down the hierarchy from QMainWindow:

              	widget = new QWidget(this);
              	widget->setObjectName("centralWidget");
              	setCentralWidget(widget);
              
              	QHBoxLayout* horizontalLayout{ new QHBoxLayout(widget) };
              	widget->setLayout(horizontalLayout);
              	ZTRACE_RUNTIME("Creating Horizontal Splitter");
              	splitter = new QSplitter(Qt::Horizontal, widget);
              	splitter->setObjectName("splitter");
              
              	ZTRACE_RUNTIME("Creating Explorer Bar (Left Panel)");
              	explorerBar = new ExplorerBar(widget);
              	explorerBar->setObjectName("explorerBar");
              	splitter->addWidget(explorerBar);
              
              	ZTRACE_RUNTIME("Creating stackedWidget");
              	stackedWidget = new QStackedWidget(splitter);
              	stackedWidget->setObjectName("stackedWidget");
              	splitter->addWidget(stackedWidget);
              
              	ZTRACE_RUNTIME("Creating Stacking Panel");
              	stackingDlg = new DSS::StackingDlg(widget);
              	stackingDlg->setObjectName("stackingDlg");
              
              	ZTRACE_RUNTIME("Adding Stacking Panel to stackedWidget");
              	stackedWidget->addWidget(stackingDlg);
              
              	winHost = new QWinHost(stackedWidget);
              	winHost->setObjectName("winHost");
              	stackedWidget->addWidget(winHost);
              
              	ZTRACE_RUNTIME("Creating Processing Panel");
              	BOOL result = processingDlg.Create(IDD_PROCESSING);
              	//processingDlg.OnInitDialog();
              
              	HWND hwnd{ processingDlg.GetSafeHwnd() };
              	Q_ASSERT(NULL != hwnd);
              	winHost->setWindow(hwnd);
              
              	splitter->setStretchFactor(1, 1);		// Want Stacking part to take any spare space.
              
              	horizontalLayout->addWidget(splitter);
              
              1 Reply Last reply
              0
              • PerdrixP Perdrix

                I sub-classed QTableView:

                #include <QTableView>
                
                class QCloseEvent;
                class QContextMenuEvent;
                
                namespace DSS
                {
                    class TableView :
                        public QTableView
                    {
                        typedef QTableView
                            Inherited;
                
                        Q_OBJECT
                
                    public:
                        explicit TableView(QWidget* parent = nullptr);
                
                        ~TableView() noexcept
                        {
                        }
                
                    protected:
                        void closeEvent([[maybe_unused]] QCloseEvent* e) override;
                
                        void contextMenuEvent([[maybe_unused]] QContextMenuEvent* event) override;
                    };
                }
                

                and in the cpp file:

                TableView::TableView(QWidget* parent) :
                	QTableView{ parent }
                {
                	QSettings settings;
                	horizontalHeader()->restoreState(
                		settings.value("Dialogs/StackingDlg/TableView/HorizontalHeader/windowState").toByteArray());
                }
                
                void TableView::closeEvent([[maybe_unused]] QCloseEvent* e)
                {
                	QSettings settings;
                	settings.setValue("Dialogs/StackingDlg/TableView/HorizontalHeader/windowState", 
                		horizontalHeader()->saveState());
                }
                
                void TableView::contextMenuEvent([[maybe_unused]] QContextMenuEvent* e)
                {
                	QMenu menu(this);
                
                	menu.exec(e->globalPos());
                }
                

                But the closeEvent mf was not called (placed a breakpoint in there)??? (The ctor was invoked)

                What am I doing wrong?

                Thanks
                David

                M Offline
                M Offline
                mpergand
                wrote on last edited by mpergand
                #6

                @Perdrix said in Saving QTableView state:

                I sub-classed QTableView:

                No need to subclass, neither for save/restore state, nor for context menu.

                As @SGaist said, do the all thing in the top level widget.
                showEvent and closeEvent for the state,
                and use customContextMenuRequested signal, see setContextMenuPolicy().

                1 Reply Last reply
                0
                • PerdrixP Offline
                  PerdrixP Offline
                  Perdrix
                  wrote on last edited by Perdrix
                  #7

                  Hmmm the closeEvent() of StackingDlg also doesn't get triggered.

                  It's a royal mess to access the tableView from the closeEvent of the QMainWindow.

                  Would the destroy() mf for StackingDlg (which owns the QTableView) be a good location to save the horizontal header state for the table view?

                  UPDATE! Arrgh QWidget::destroy() isn't virtual so I can't use that!

                  So what can I use simply to detect the one of my Widgets is going away.

                  PS setting the context menu policy for the table view to Qt::CustomContextMenu and having:

                  void StackingDlg::on_tableView_customContextMenuRequested(const QPoint& pos)
                  

                  is a really nice way to handle the popup menu!

                  Thanks
                  David

                  M 1 Reply Last reply
                  0
                  • PerdrixP Perdrix

                    Hmmm the closeEvent() of StackingDlg also doesn't get triggered.

                    It's a royal mess to access the tableView from the closeEvent of the QMainWindow.

                    Would the destroy() mf for StackingDlg (which owns the QTableView) be a good location to save the horizontal header state for the table view?

                    UPDATE! Arrgh QWidget::destroy() isn't virtual so I can't use that!

                    So what can I use simply to detect the one of my Widgets is going away.

                    PS setting the context menu policy for the table view to Qt::CustomContextMenu and having:

                    void StackingDlg::on_tableView_customContextMenuRequested(const QPoint& pos)
                    

                    is a really nice way to handle the popup menu!

                    Thanks
                    David

                    M Offline
                    M Offline
                    mpergand
                    wrote on last edited by
                    #8

                    @Perdrix said in Saving QTableView state:

                    It's a royal mess to access the tableView from the closeEvent of the QMainWindow.

                    Why ?

                    stackingDlg = new DSS::StackingDlg(widget);
                    stackingDlg->setObjectName("stackingDlg");
                    

                    stackingDlg not a variable of your mainWindow ?
                    you can even retrieve it by its name ;)

                    1 Reply Last reply
                    0
                    • PerdrixP Offline
                      PerdrixP Offline
                      Perdrix
                      wrote on last edited by Perdrix
                      #9

                      Arrghh forgot I was saving that in the class !!!

                      Except of course ui is private in DSS:StackingDlg. So I had to make the main window a friend of DSS::StackingDlg

                      And it worked fine

                      Thanks all
                      D.

                      1 Reply Last reply
                      0
                      • PerdrixP Offline
                        PerdrixP Offline
                        Perdrix
                        wrote on last edited by Perdrix
                        #10

                        The final code to save the state of the Horizontal header in the QMainWindow::closeEvent handler reads like this:

                        QSettings settings;
                        settings.setValue("geometry", saveGeometry());
                        settings.setValue("windowState", saveState());
                        QTableView* tableView = this->findChild<QTableView*>("tableView");
                        settings.setValue("Dialogs/StackingDlg/TableView/HorizontalHeader/windowState",
                        	tableView->horizontalHeader()->saveState());
                        

                        it relies on the tableView object being named but that is normally true.
                        David

                        JonBJ 1 Reply Last reply
                        1
                        • PerdrixP Perdrix

                          The final code to save the state of the Horizontal header in the QMainWindow::closeEvent handler reads like this:

                          QSettings settings;
                          settings.setValue("geometry", saveGeometry());
                          settings.setValue("windowState", saveState());
                          QTableView* tableView = this->findChild<QTableView*>("tableView");
                          settings.setValue("Dialogs/StackingDlg/TableView/HorizontalHeader/windowState",
                          	tableView->horizontalHeader()->saveState());
                          

                          it relies on the tableView object being named but that is normally true.
                          David

                          JonBJ Offline
                          JonBJ Offline
                          JonB
                          wrote on last edited by JonB
                          #11

                          @Perdrix said in Saving QTableView state:

                          it relies on the tableView object being named but is normally true.

                          Is this a statement about what you are "happy" with as your behaviour, or something you might like improved? Just a couple of comments:

                          • IF you have only one table view then (are you aware that) you can omit the object name and just go this->findChild<QTableView*>(), so you do not have to set any object name on it?

                          • If you have more than one, which one are you looking for to be saved under Dialogs/StackingDlg/TableView/HorizontalHeader/windowState?

                          • Instead of relying on the object name, you might consider adding a property to the/those table view(s) to indicate this is/should be "saved", and search among all table views for that/those which have this property.

                          • Of course, you could also subclass the QTableView to, say, a QSaveableTableView and search for that class.

                          PerdrixP 1 Reply Last reply
                          1
                          • JonBJ JonB

                            @Perdrix said in Saving QTableView state:

                            it relies on the tableView object being named but is normally true.

                            Is this a statement about what you are "happy" with as your behaviour, or something you might like improved? Just a couple of comments:

                            • IF you have only one table view then (are you aware that) you can omit the object name and just go this->findChild<QTableView*>(), so you do not have to set any object name on it?

                            • If you have more than one, which one are you looking for to be saved under Dialogs/StackingDlg/TableView/HorizontalHeader/windowState?

                            • Instead of relying on the object name, you might consider adding a property to the/those table view(s) to indicate this is/should be "saved", and search among all table views for that/those which have this property.

                            • Of course, you could also subclass the QTableView to, say, a QSaveableTableView and search for that class.

                            PerdrixP Offline
                            PerdrixP Offline
                            Perdrix
                            wrote on last edited by Perdrix
                            #12

                            @JonB said in Saving QTableView state:

                            Is this a statement about what you are "happy" with

                            Yes, I am happy with the normal default behaviour.

                            I wasn't aware of all the stuff in your reply, but all are useful bits of information.

                            I only have one table view to worry about :)

                            Thanks
                            D.

                            1 Reply Last reply
                            1

                            • Login

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