Friday, November 12, 2010

Passing Parameters to a QMetaObject in Qt

The target scenario is as follows:
- Window(A) calls Window(B) and then Window(A) is closed.
- When Window(B) is closed we want to go back to Window(A). But Window(A) needs some parameters in the constructor. How to know these parameters, an the exact values?

One solution is to pass the previously known parameters from (A) to (B), then when (B) is destroyed, it will create an instance from (A) with these parameters. But this is not generic, because if (B) is called in an application by two different windows, how do we know which Window(A or C) called it?
To make the process more generic, here is a solution:

In Window(A): make a 'struct' containing all the parameters needed by the constructor.

Make a new constructor for class (A) that takes a void pointer (void* myPointer) and has a macro Q_INVOKABLE before it.

WindowA(int number, QString text);
Q_INVOKABLE WindowA(void* params);

In the original constructor, save the parameters in the struct you made

c_params->number = number;
c_params->text = text;

And when calling Window(B) you pass the "staticMetaObject" of the current class and the struct instance as a void pointer.

WindowB* b1 = 
    new WindowB(WindowA::staticMetaObject, (void*)c_params);

Note: the WindowA must have a Q_OBJECT macro it its definition.

class WindowA : public QMainWindow

    WindowA(int number, QString text, QWidget *parent = 0);
    Q_INVOKABLE WindowA(void* params, QWidget *parent = 0);
    Ui::WindowA *ui;
    ClassParam *c_params;
private slots:
    void on_pushButton_clicked();

and of course the constructor of WindowB may look like this (and can have any extra needed parameters):
WindowB(QMetaObject metaobject, void* params);

We save these parameters in some local variables to be used later.

    QMetaObject parentForm;
    void* c_params;

And whenever we want to call ClassA, we do as follows:
QMainWindow* w = 
    (QMainWindow*)(parentForm.newInstance(Q_ARG(void*, c_params)));

Here I casted the parent form instance as a QMainWindow because it inherits from it.
Note that the parameters passed in the newInstance() method are passed in a void pointer. And to do this, I used the macro Q_ARG(void*, c_params) which takes the type of the parameter (void*) and the data (c_params).

Now we move back to WindowA to see how it works.
This time the invokable constructor is the one to be called:
Q_INVOKABLE ClassA(void* params);

inside this constructor I cast the void pointer as struct pointer, and then I can read its data and do whatever I want.

c_params = (ClassParam*)params;
int i = c_params->number;
QString s = c_params->text;

A simple example is attached, and has some comments for a clearer understanding.

Creative Commons License
Blog Example by Mahmoud Adly Ezzat is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.

No comments:

Post a Comment