[Qt-interest] Refactoring app to use QStackedWidgets with opaque widget pointers, rather than one large QStackedWidgets to cut compilation dependencies
André Fillipe
andref at syst.com.br
Sun Nov 29 03:48:01 CET 2009
2009/11/27 John Moran <johnfrederickmoran at gmail.com>
> Hello,
>
Hi, John
I'm working on an Qt embedded application, that mostly consists of a
> single QWidget that displays a QStackedWidget. Each page of the
> stacked widget consists of collections of widgets like QPushButtons
> and so on.
The project I'm currently working on has an identical structure: we use a
QStackedWidget to selectively show different "pages" to the user as she
navigates through the system. In our case, however, each of those pages is a
separate form class (each with its own .ui file) and we have a controller
class that assembles the widget stack and listens for signals from the
individual pages to control navigation.
We keep the code of the pages as simple as possible and put most of the
logic inside the controller. If the pages had complex logic, a better
solution would be to give each page its own controller and use a skinny
PageDirector class to handle navigation (were it released, QStateMachine
would have been a lot of help).
This setup worked quite nicely for us. It allowed us to assign pages to
different developers and bought us a little more time to develop the
application shell that wasn't ready yet. The developers could just have the
controller show() the QStackedWidget to test the app.
> One possible fix is to have the existing UI file's stacked widget just
> contain other UI classes (that are somehow opaque; i.e. had their UI
> classes declared but not defined). We then have a bunch of opaque
> pointers in "mainwidget"'s definition; the existing UI, plus a bunch
> of them for each page's UI class. We then selectively include only
> those definitions that are needed in each CPP file of "mainwidget"'s
> implementation, and avoid having to re-compile the entirety of the
> rather large, multiple translation unit file every time I change my
> main .ui file.
>
I see two possibilities. The first is to create a separate class for each of
the pages, but I believe you'd have to redesign a lot of what is already
working. Another would be to dynamically load the .ui file for each of the
pages using QUiLoader <http://doc.trolltech.com/4.5/quiloader.html>. It's
been a while since I used QUiLoader, but the code would look a bit like
this:
template <typename T>
T* mainwindow::find(Qwidget* where, const QString& name)
{
// Caching the result is a good idea.
T* widget = qFindChild<T*>(where, name);
if (!widget) {
qWarning() << "Oops! Didn't find" << name
<< "anywhere. Expect a crash!";
}
return widget;
}
void mainwidget::setup()
{
QUiLoader loader;
QFile file1(":/pages/page1.ui");
file1.open(QFile::ReadOnly);
this->first_page = loader.load(&file1, this);
file1.close();
QFile file2(":/pages/page2.ui");
file2.open(QFile::ReadOnly);
this->second_page = loader.load(&file2, this);
file2.close();
// etc...
this->stack->addWidget(first_page);
this->stack->addWidget(second_page);
}
void mainwidget::something()
{
// Since there are no explicit instance variables for
// the widgets, use find<T> to dynamically access them.
find<QLabel>(first_page, "logo")->setPixmap(my_pixmap);
}
QUiLoader can be reimplemented if you need better control on how widgets are
created, so I think this can be improved a lot. I believe it also
auto-connects slots, but I haven't tried. Bonus: if during development you
don't put the .ui files in a resource, you get to modify the user interface
and see the results without having to recompile.
I hope this helps you somehow.
--
André Fillipe
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.qt-project.org/pipermail/qt-interest-old/attachments/20091129/f5c18562/attachment.html
More information about the Qt-interest-old
mailing list