Ok this is going to be quite a long post:
I'm building an application for Qt for Symbian. Like I said before the idea of my application is built on a stack solution looking like this: I have one stacked widget. The first widget in the stacked widget is a kind of home screen. It has a list of categories. When the user clicks a category a new widget is added to the stacked widget with a list of sub categories. If the user clicks a sub category a new widget is added with a new list. The user clicks through the lists, and these steps can differ depending on user choices on the way. So the same widgets maybe wont be added in the same order each time. At last a widget shows where the user can edit items. When the user have saved the changes of an item he get sent back to the home screen and all the other widgets should get deleted from the stack.
It should look something like this:
Home screen->Categories->SOME STEPS->Items->Edit Item->Save---->
<-----------------back to home screen, delete all widgets------------
To be able to solve this I have subclassed QStackedWidget with my own CustomStackedWidget. The CustomStackedWidget can insert new widgets into the stack, remove them, and pop back to the home screen. This is my CustomStackedWidget:
CustomStackedWidget.h:
{
Q_OBJECT
public:
CustomStackedWidget
(QWidget *parent
);
virtual ~CustomStackedWidget();
//Pops the stack
virtual void popTo(int index);
// Activates existing view
virtual void activateWidget
(QWidget* widgetToFind
);
// Removes view
virtual void removeWidgetWithWidget
(QWidget* widget
);
// Activates new view.
virtual void activateNewWidget
(QWidget* newWidget
);
public slots:
// Activates previous view and deletes current
virtual void activatePreviousView();
};
class CustomStackedWidget : public QStackedWidget
{
Q_OBJECT
public:
CustomStackedWidget(QWidget *parent);
virtual ~CustomStackedWidget();
//Pops the stack
virtual void popTo(int index);
// Activates existing view
virtual void activateWidget(QWidget* widgetToFind);
// Removes view
virtual void removeWidgetWithWidget(QWidget* widget);
// Activates new view.
virtual void activateNewWidget(QWidget* newWidget);
public slots:
// Activates previous view and deletes current
virtual void activatePreviousView();
};
To copy to clipboard, switch view to plain text mode
CustomStackedWidget.cpp:
#include "CustomStackedWidget.h"
CustomStackedWidget
::CustomStackedWidget(QWidget *parent
){
}
CustomStackedWidget::~CustomStackedWidget()
{
// TODO Auto-generated destructor stub
}
void CustomStackedWidget::popTo(int index){
this->setCurrentWidget(this->widget(index));
for(int i = this->count(); i > index; i--){
this->removeWidgetWithWidget(widget);
}
}
void CustomStackedWidget
::activateWidget(QWidget* widgetToFind
){ for (int i=0; i < this->count(); i++)
{
if (widget == widgetToFind)
{
this->setCurrentWidget(widget);
break;
}
}
}
void CustomStackedWidget
::activateNewWidget(QWidget* newWidget
){ this->addWidget(newWidget);
activateWidget(newWidget);
}
void CustomStackedWidget
::removeWidgetWithWidget(QWidget* widget
) {
this->removeWidget(widget);
widget->deleteLater();
}
void CustomStackedWidget::activatePreviousView()
{
QWidget *currentWidget
= this
->currentWidget
();
for (int i=0; i < this->count(); i++)
{
if (widget==currentWidget)
{
if (i>0)
{
i--;
previous = this->widget(i);
// Remove current widget
this->removeWidgetWithWidget(currentWidget);
// Activate previous widget
activateWidget(previous);
}
break;
}
}
}
#include "CustomStackedWidget.h"
CustomStackedWidget::CustomStackedWidget(QWidget *parent)
: QStackedWidget(parent)
{
}
CustomStackedWidget::~CustomStackedWidget()
{
// TODO Auto-generated destructor stub
}
void CustomStackedWidget::popTo(int index){
this->setCurrentWidget(this->widget(index));
for(int i = this->count(); i > index; i--){
QWidget* widget = this->widget(i);
this->removeWidgetWithWidget(widget);
}
}
void CustomStackedWidget::activateWidget(QWidget* widgetToFind){
for (int i=0; i < this->count(); i++)
{
QWidget* widget = this->widget(i);
if (widget == widgetToFind)
{
this->setCurrentWidget(widget);
break;
}
}
}
void CustomStackedWidget::activateNewWidget(QWidget* newWidget){
this->addWidget(newWidget);
activateWidget(newWidget);
}
void CustomStackedWidget::removeWidgetWithWidget(QWidget* widget)
{
this->removeWidget(widget);
widget->deleteLater();
}
void CustomStackedWidget::activatePreviousView()
{
QWidget *currentWidget = this->currentWidget();
QWidget *previous;
for (int i=0; i < this->count(); i++)
{
QWidget* widget = this->widget(i);
if (widget==currentWidget)
{
if (i>0)
{
i--;
previous = this->widget(i);
// Remove current widget
this->removeWidgetWithWidget(currentWidget);
// Activate previous widget
activateWidget(previous);
}
break;
}
}
}
To copy to clipboard, switch view to plain text mode
Every widget that I insert into the stack is a sub class of my own widget MyWidget. To make it simple, in this example the UI of MyWidget just consist of one label showing which index in the stack the widget has. The UI also has one button to insert another widget, one button to remove the current widget and another one to pop to the first widget in the stack. This is just to show you the idea, in the real application the widget can have a lot of more stuff in it. This is MyWidget:
MyWidget.h:
{
Q_OBJECT
public:
MyWidget
(CustomStackedWidget
*stackedWidget,
QWidget *parent
= 0);
MyWidget
(int index, CustomStackedWidget
*stackedWidget,
QWidget *parent
= 0);
~MyWidget();
CustomStackedWidget *stackedWidget;
int index;
private:
Ui::MyWidgetClass ui;
private slots:
void on_pushButtonRemove_clicked();
void on_pushButtonInsert_clicked();
void on_pushButtonPop_clicked();
};
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(CustomStackedWidget *stackedWidget, QWidget *parent = 0);
MyWidget(int index, CustomStackedWidget *stackedWidget, QWidget *parent = 0);
~MyWidget();
CustomStackedWidget *stackedWidget;
int index;
private:
Ui::MyWidgetClass ui;
private slots:
void on_pushButtonRemove_clicked();
void on_pushButtonInsert_clicked();
void on_pushButtonPop_clicked();
};
To copy to clipboard, switch view to plain text mode
MyWidget.cpp:
MyWidget
::MyWidget(CustomStackedWidget
*stackedWidget,
QWidget *parent
){
ui.setupUi(this);
}
MyWidget
::MyWidget(int index, CustomStackedWidget
*stackedWidget,
QWidget *parent
){
ui.setupUi(this);
this->stackedWidget = stackedWidget;
this->index = index;
ui.
label->setText
(QString::number(index,
10));
}
MyWidget::~MyWidget()
{
}
void MyWidget::on_pushButtonRemove_clicked() {
this->stackedWidget->activatePreviousView();
}
void MyWidget::on_pushButtonInsert_clicked() {
MyWidget *newMyWidget = new MyWidget(this->index+1,this->stackedWidget);
this->stackedWidget->activateNewWidget(newMyWidget);
}
void MyWidget::on_pushButtonPop_clicked() {
this->stackedWidget->popTo(0);
}
MyWidget::MyWidget(CustomStackedWidget *stackedWidget, QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
}
MyWidget::MyWidget(int index, CustomStackedWidget *stackedWidget, QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
this->stackedWidget = stackedWidget;
this->index = index;
ui.label->setText(QString::number(index,10));
}
MyWidget::~MyWidget()
{
}
void MyWidget::on_pushButtonRemove_clicked() {
this->stackedWidget->activatePreviousView();
}
void MyWidget::on_pushButtonInsert_clicked() {
MyWidget *newMyWidget = new MyWidget(this->index+1,this->stackedWidget);
this->stackedWidget->activateNewWidget(newMyWidget);
}
void MyWidget::on_pushButtonPop_clicked() {
this->stackedWidget->popTo(0);
}
To copy to clipboard, switch view to plain text mode
You can see my test project in full here:
http://www.easy-share.com/1909777246...WidgetTest.rar
The problem that I'm having is that if I insert a lot of widgets into the stack and then pop back to the home screen and then do this like 5-10 times I got a memory warning (this have been tested on both Nokia N97 and Nokia 5800). This memory warning doesn't show on this small test project, as it is very light-weighted widgets that I use in the test. In the real application these widgets is more heavy. But I'm just curious if the solution I'm using seems right. If you wan't I could give you the full (giant) project but I really can't post it here.
1. The widgets in the stacked widget should they all have the stacked widget as parent? It maybe doesn't matter as I always delete the widgets by my own when they are removed from the stacked widget?
2. As you can see I'm using deleteLater to delete my widgets. It wouldn't really matter if I used delete instead as I always do deleteLater as the last thing and then the control returns to the event loop and the widget will be deleted?
3. Is this a good approach at all? Should I think of another way instead of adding and deleting my widgets like this? The different steps that the user can take when using the application is quite complex so it seemed easy to just add and deleting like this without reuse the widgets. How would a solution where I reuse the widgets look like?
I have been working with solving this for over a week and I would be very very glad for all help I can get. Thanks!
Bookmarks