Solved How to properly manage a Multi-Page application (without QStackedWidget)
-
Hi @JonB, I want to create a totally new page.
-
@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 ( viaCreate
).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 necessarynew
s 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. -
@JonB
thanks for your point of view. I'll read this quickly but also trying to understand it ;) -
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); }
-
@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. -
This post is deleted! -
@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);
^~~~~~~~~~~~~~~~~~~
-
-
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.
-
-
I use the old syntax. But the problem is at the slot declaration level.
This do not compilepublic 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);
-
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();