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. How to properly manage a Multi-Page application (without QStackedWidget)
Forum Updated to NodeBB v4.3 + New Features

How to properly manage a Multi-Page application (without QStackedWidget)

Scheduled Pinned Locked Moved Solved General and Desktop
13 Posts 4 Posters 3.5k Views 2 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.
  • F Offline
    F Offline
    Foufy
    wrote on last edited by Foufy
    #1

    Hi Everyone,
    I'm trying to create a UI with lot of pages. I know that QStackedWidget Class can do the job but because the target is a raspberry pi I don't want to load all pages (i.e. QFrame) in the memory. Thus I'm trying to create/delete each Pages to replace the QMainWindow::centralWidget. Note that each Pages is a Class which inherits from QFrame. That works.

    But, I want to include a [BACK] button and so I need to save the previous Page constructor to recall it when this button is pressed. I'm trying to use function pointer pointing on a static "factory" method defined in each Page Class.

    Page1::Page1(QWidget *parent) : QFrame (parent){}
    Page1* Page1::factory() { return new Page1();}
    

    Because each page is an instance of a different class i can't do this :

    Page1* (*previousPage) (void);
    previousPage = &Page1::factory;
    

    What I'm trying to do is to use the centralWidget to pointing to their factory method.
    Maybe is not the good strategy to managed multiPage including a [back] button.
    Can you help me please.
    Thanks

    Foufy

    JonBJ Pl45m4P 2 Replies Last reply
    0
    • F Foufy

      Hi Everyone,
      I'm trying to create a UI with lot of pages. I know that QStackedWidget Class can do the job but because the target is a raspberry pi I don't want to load all pages (i.e. QFrame) in the memory. Thus I'm trying to create/delete each Pages to replace the QMainWindow::centralWidget. Note that each Pages is a Class which inherits from QFrame. That works.

      But, I want to include a [BACK] button and so I need to save the previous Page constructor to recall it when this button is pressed. I'm trying to use function pointer pointing on a static "factory" method defined in each Page Class.

      Page1::Page1(QWidget *parent) : QFrame (parent){}
      Page1* Page1::factory() { return new Page1();}
      

      Because each page is an instance of a different class i can't do this :

      Page1* (*previousPage) (void);
      previousPage = &Page1::factory;
      

      What I'm trying to do is to use the centralWidget to pointing to their factory method.
      Maybe is not the good strategy to managed multiPage including a [back] button.
      Can you help me please.
      Thanks

      Foufy

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

      @Foufy
      Before you go any further with this strategy. When user goes Back do you expect them to get back to the previous page with all state (e.g. widgets) just as it was, or do you expect them to always have to restart from a brand new page in its initial state? because you're going to get the latter, and you may say you actually want the former

      F 1 Reply Last reply
      0
      • F Offline
        F Offline
        Foufy
        wrote on last edited by Foufy
        #3
        This post is deleted!
        1 Reply Last reply
        0
        • JonBJ JonB

          @Foufy
          Before you go any further with this strategy. When user goes Back do you expect them to get back to the previous page with all state (e.g. widgets) just as it was, or do you expect them to always have to restart from a brand new page in its initial state? because you're going to get the latter, and you may say you actually want the former

          F Offline
          F Offline
          Foufy
          wrote on last edited by Foufy
          #4

          Hi @JonB, I want to create a totally new page.

          JonBJ 1 Reply Last reply
          0
          • F Foufy

            Hi @JonB, I want to create a totally new page.

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

            @Foufy
            I am not a C++ expert. So I cannot be sure my answer is correct, but I do not think you can achieve what you want via your simple approach.

            C++ templates may help you. Have a look at
            https://gist.github.com/sacko87/3359911
            https://stackoverflow.com/questions/4357500/c-abstract-factory-using-templates
            http://blog.fourthwoods.com/2011/06/04/factory-design-pattern-in-c/ (looks scary to me)
            https://www.codeproject.com/Articles/363338/Factory-Pattern-in-Cplusplus looks fairly simple to me (no templates), but you would have to read through the comments, because I think some people are saying it is not good design.

            At the end of the day they (mostly?) use a pattern of the factory linking a string name (via Register) for the desired class with a constructor for that class ( via Create).

            Depending on just how many classes of pages you have to deal with, you could cut out all the complications and just go for explicit code with a switch/if else if directly calling the necessary news and then it's done without arguing....

            One other way would be a dynamically-populated QStackedWidget with the pages, but not pre-created with all page types, rather only those in the currently Backable navigation. Remove pages from the stack once they cannot be Backed into. This would be more like when I asked whether you want to preserve previous state. It will take up more space than no-saved-stack, though not as much as all-pre-created, which you may say is unacceptable for your RPi memory, I don't know.

            F 1 Reply Last reply
            1
            • JonBJ JonB

              @Foufy
              I am not a C++ expert. So I cannot be sure my answer is correct, but I do not think you can achieve what you want via your simple approach.

              C++ templates may help you. Have a look at
              https://gist.github.com/sacko87/3359911
              https://stackoverflow.com/questions/4357500/c-abstract-factory-using-templates
              http://blog.fourthwoods.com/2011/06/04/factory-design-pattern-in-c/ (looks scary to me)
              https://www.codeproject.com/Articles/363338/Factory-Pattern-in-Cplusplus looks fairly simple to me (no templates), but you would have to read through the comments, because I think some people are saying it is not good design.

              At the end of the day they (mostly?) use a pattern of the factory linking a string name (via Register) for the desired class with a constructor for that class ( via Create).

              Depending on just how many classes of pages you have to deal with, you could cut out all the complications and just go for explicit code with a switch/if else if directly calling the necessary news and then it's done without arguing....

              One other way would be a dynamically-populated QStackedWidget with the pages, but not pre-created with all page types, rather only those in the currently Backable navigation. Remove pages from the stack once they cannot be Backed into. This would be more like when I asked whether you want to preserve previous state. It will take up more space than no-saved-stack, though not as much as all-pre-created, which you may say is unacceptable for your RPi memory, I don't know.

              F Offline
              F Offline
              Foufy
              wrote on last edited by
              #6

              @JonB
              thanks for your point of view. I'll read this quickly but also trying to understand it ;)

              1 Reply Last reply
              0
              • F Offline
                F Offline
                Foufy
                wrote on last edited by Foufy
                #7

                What about if each of Page's class emits a Signal such :

                #include "Page2.h"
                Class Page1: public QFrame
                {
                public:
                   static QFrame* factory();
                
                signals:
                   void frameChanged(QFrame* (*previousFrame)(void), QFrame* nextFrame);
                }
                

                and when a new page is created in Page1.cpp

                void Page1::onNextPageClicked()
                {
                   emit frameChanged(&Page1::factory, new Page2);
                }
                
                JonBJ F 2 Replies Last reply
                0
                • F Foufy

                  What about if each of Page's class emits a Signal such :

                  #include "Page2.h"
                  Class Page1: public QFrame
                  {
                  public:
                     static QFrame* factory();
                  
                  signals:
                     void frameChanged(QFrame* (*previousFrame)(void), QFrame* nextFrame);
                  }
                  

                  and when a new page is created in Page1.cpp

                  void Page1::onNextPageClicked()
                  {
                     emit frameChanged(&Page1::factory, new Page2);
                  }
                  
                  JonBJ Offline
                  JonBJ Offline
                  JonB
                  wrote on last edited by
                  #8

                  @Foufy
                  That, and whether you do or do not emit signals, has no connection to your question about how/whether to create a factory for the various page classes you have.

                  1 Reply Last reply
                  0
                  • N Offline
                    N Offline
                    nona1000
                    Banned
                    wrote on last edited by
                    #9
                    This post is deleted!
                    1 Reply Last reply
                    0
                    • F Foufy

                      What about if each of Page's class emits a Signal such :

                      #include "Page2.h"
                      Class Page1: public QFrame
                      {
                      public:
                         static QFrame* factory();
                      
                      signals:
                         void frameChanged(QFrame* (*previousFrame)(void), QFrame* nextFrame);
                      }
                      

                      and when a new page is created in Page1.cpp

                      void Page1::onNextPageClicked()
                      {
                         emit frameChanged(&Page1::factory, new Page2);
                      }
                      
                      F Offline
                      F Offline
                      Foufy
                      wrote on last edited by
                      #10

                      @Foufy
                      I've test what i suggested but can't compile (Qt5.12.1). It seems not possible to pass a function pointer by signal/slot. I have the following error

                      • ./build-TestMultiPage-Desktop_Qt_5_12_1_GCC_64bit-Debug/moc_mainwindow.cpp:78: erreur : no matching function for call to ‘MainWindow::onCenterFrameChanged(QFrame*&, QFrame*&)’
                        case 1: _t->onCenterFrameChanged((reinterpret_cast< QFrame()>(_a[1])),(reinterpret_cast< QFrame()>(_a[2]))); break;

                      • list item../TestMultiPage/mainwindow.h:24: candidate: void MainWindow::onCenterFrameChanged(QFrame* ()(), QFrame)
                        void onCenterFrameChanged(QFrame*(previousFrame)(void),QFrame nextFrame);
                        ^~~~~~~~~~~~~~~~~~~

                      1 Reply Last reply
                      0
                      • F Foufy

                        Hi Everyone,
                        I'm trying to create a UI with lot of pages. I know that QStackedWidget Class can do the job but because the target is a raspberry pi I don't want to load all pages (i.e. QFrame) in the memory. Thus I'm trying to create/delete each Pages to replace the QMainWindow::centralWidget. Note that each Pages is a Class which inherits from QFrame. That works.

                        But, I want to include a [BACK] button and so I need to save the previous Page constructor to recall it when this button is pressed. I'm trying to use function pointer pointing on a static "factory" method defined in each Page Class.

                        Page1::Page1(QWidget *parent) : QFrame (parent){}
                        Page1* Page1::factory() { return new Page1();}
                        

                        Because each page is an instance of a different class i can't do this :

                        Page1* (*previousPage) (void);
                        previousPage = &Page1::factory;
                        

                        What I'm trying to do is to use the centralWidget to pointing to their factory method.
                        Maybe is not the good strategy to managed multiPage including a [back] button.
                        Can you help me please.
                        Thanks

                        Foufy

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

                        @Foufy

                        I dont know if it works in your case, but have you tried using a QList / QVector or something to store the name or the object in a List (FILO, first in last out)?
                        When the "Back"-Btn is pressed, you detroy / replace the active widget, call the constructor of the last widget from your QLIst and set it as CentralWidget...

                        @Foufy said in How to properly manage a Multi-Page application (without QStackedWidget):

                        I've test what i suggested but can't compile (Qt5.12.1). It seems not possible to pass a function pointer by signal/slot. I have the following error

                        Are you using the new signal&slot syntax or the old one?
                        With the new one, you can pass nearly everything (compiler will check, if it is possible).

                        From https://wiki.qt.io/New_Signal_Slot_Syntax:

                        • Pros

                          • Compile time check of the existence of the signals and slot, of the types, or if the Q_OBJECT is missing.
                          • Argument can be by typedefs or with different namespace specifier, and it works.
                          • Possibility to automatically cast the types if there is implicit conversion (e.g. from QString to QVariant)
                          • It is possible to connect to any member function of QObject, not only slots.

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

                        ~E. W. Dijkstra

                        F 1 Reply Last reply
                        0
                        • Pl45m4P Pl45m4

                          @Foufy

                          I dont know if it works in your case, but have you tried using a QList / QVector or something to store the name or the object in a List (FILO, first in last out)?
                          When the "Back"-Btn is pressed, you detroy / replace the active widget, call the constructor of the last widget from your QLIst and set it as CentralWidget...

                          @Foufy said in How to properly manage a Multi-Page application (without QStackedWidget):

                          I've test what i suggested but can't compile (Qt5.12.1). It seems not possible to pass a function pointer by signal/slot. I have the following error

                          Are you using the new signal&slot syntax or the old one?
                          With the new one, you can pass nearly everything (compiler will check, if it is possible).

                          From https://wiki.qt.io/New_Signal_Slot_Syntax:

                          • Pros

                            • Compile time check of the existence of the signals and slot, of the types, or if the Q_OBJECT is missing.
                            • Argument can be by typedefs or with different namespace specifier, and it works.
                            • Possibility to automatically cast the types if there is implicit conversion (e.g. from QString to QVariant)
                            • It is possible to connect to any member function of QObject, not only slots.
                          F Offline
                          F Offline
                          Foufy
                          wrote on last edited by
                          #12

                          @Pl45m4

                          I use the old syntax. But the problem is at the slot declaration level.
                          This do not compile

                          public slots:
                              void onCenterFrameChanged(QFrame*(*previousFrame)(void),QFrame* nextFrame);
                          

                          But compilation is OK if I declare a method (instead of a slot) like this

                          public:
                              void onCenterFrameChanged(QFrame*(*previousFrame)(void),QFrame* nextFrame);
                          
                          1 Reply Last reply
                          0
                          • F Offline
                            F Offline
                            Foufy
                            wrote on last edited by Foufy
                            #13

                            I finally found a solution

                            #include <QFrame>
                            
                            class AbstractPage : public QFrame
                            {
                                Q_OBJECT
                            public:
                                explicit AbstractPage(QWidget *parent = nullptr){};
                                virtual AbstractPage* (*getFactory())() = 0;
                            };
                            

                            An exemple of a Page

                            #include "abstractframe.h"
                            
                            class Page1 : public AbstractFrame
                            {
                                Q_OBJECT
                            public:
                                explicit Page1(QWidget *parent = nullptr);
                            
                                inline static  AbstractFrame* factory(){return new Page1;};
                                inline AbstractFrame* (*getFactory())() {return &Page1::factory;};
                            
                            private slots:
                                void onButtonClicked(bool);
                            
                            signals:
                                void frameChanged(AbstractFrame*);
                            };
                            

                            And generate a new Page using

                            AbstractFrame *(*previousFrame)() = mCenterFrame->getFactory(); 
                            // and after create the Frame
                            mCenterFrame = previousFrame();
                            
                            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