QWIzardPage parent() method returning NULL pointer inside initializePage()



  • So still very new to Qt, but decent programmer (I'd like to think). I'm currently porting some code from a VS solution to Qt and attempting to keep most of the logic. It heavily uses MFC...

    I designed the QWizardPage and its "parent" QWizard class under the designer.

    Inside my initializePage() method I want to get the pointer to my parent, SxtWizard, and do some stuff with a few of it's members. But... the inherited parent() method from QObject only returns a NULL pointer... This is the way its done in the code I'm porting, but I'm completely open to suggestions with doing things differently. Should I even be using parent()!? Just add member that is set to "parent" in the constructor and use it? (think that works btw...)

    Also something to note, the QWizard dialog is shown after a button is clicked on a different dialog (there will be multiple wizards).

    So my QWizardPage class:

    @
    #include "inputinfo.h"
    #include "ui_inputinfo.h"
    #include "sxtwizard.h"

    InputInfo::InputInfo(SxtWizard* parent) : QWizardPage(parent), ui(new Ui::InputInfo),
    maxSpeed(0), minSpeed(0),
    ...
    {
    this->setupUi(this);
    }

    void InputInfo::initializePage()
    {
    SxtWizard wizard = dynamic_cast<SxtWizard>(this->parent()); //this returns a null pointer! :(
    ...do some stuff...
    }
    @
    Now the QWizard class:
    @
    #include "ui_sxtwizard.h"
    #include "inputinfor.h"
    #include "sxtwizard.h"

    SxtWizard::SxtWizard(QWidget *parent) : QWizard(parent), ui(new Ui::SxtWizard)
    , exportData(NULL), ...
    {
    ui->setupUi(this);
    addPage(new InputInfo(this));
    }
    @

    Iv looked at "this ":http://qt-project.org/forums/viewthread/15838 thread for awhile...but to no avail.

    What am I doing wrong!?


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    First, you should use qobject_cast since you are casting a derived class of QObject. Then can you check what this->parent() points to before casting ?

    As a side note, it's generally a bad design for a child to have to know the parent to get some information from it, it creates a tight coupling that should be avoided as much a possible to keep a clean and maintainable code.

    Hope it helps



  • First of all thank you for the replay SGaist!

    Sorry I had tested both dynamic_cast and qobject_cast, both return a null pointer.

    Using the debugger inside the constructor if I traverse this -> ... -> QObject -> ... ->parent: There's an additional value with "Name" as "_vtcast_SxtWizard", "Value" as "class SxtWizard" and "Type" as "SxtWizard".

    Doing the same thing inside of initializePage() method when traversing the same "this" pointer there is no (name. value, type) tuple mentioned in the constructor. Any ideas...?

    Also side question... I think I know the answer but want to confirm. What exactly is the Qt mechanism to having actual data (class members, etc..) linked (not sure on terminology) to widgets? Like having a QString linked to a QTextBrowser, and when the string I changed its reflected/updated inside the widget. Is this accomplished by using the Property System? (using value changed or something...?)

    Thanks again for your help...


  • Lifetime Qt Champion

    Are you missing the Q_OBJECT macro ?

    Also what does this->parent() (without any casting) return in initializePage ?

    Indeed, Property System + Signals and Slots. You can see this in the examples throughout the documentation



  • I have the Q_OBJECT macro declared in both header files...that's the only place where its needed right?

    And I can do:
    @
    Qbject test = this->parent(); @

    and get back a valid pointer.

    But...I finally got it! But want to know why...
    @
    SxtWizard* test = qobject_cast<SxtWizard*>(this->parent()->parent()->parent()); @

    returns the correct pointer... I know I'm doing something wrong now...


  • Lifetime Qt Champion

    If you print each ancestor you'll find the chain of parenting and it probably contains a layout manager.

    As I said before, the child should not know about it's parent/ancestors. It's the wizard duty to setup the page, not the page to try and discover it's wizard ancestor and take information from it.



  • Yea...its a layout manger... bleh Well at this point I was just curious on what was going on... But I'v changed the logic to have the QWizard sets the pointers and adds the page after.

    Thanks for your help! :D


  • Lifetime Qt Champion

    You're welcome !

    What pointer does your QWizard set ?



  • There are two pointers to set to separate class instances, each holding a hefty amount of data (strings, floats, other pointers). In the code I am porting they set them in the OnInitDialog() method for a CPropertyPage (MFC), which I guessed would be similar to the initalizePage() method for QWizardPage. But I can change what I see fit thankfully lol..

    Im still having trouble using properties and signal/slots... I have a QWizardPage and a QTextBrowser. Suppose I have the following header:

    @
    class MyClass : public QWizardPage
    {
    Q_OBJECT
    Q_PROPERTY(QString dbName READ getDbName WRITE setDbName)
    public:
    QString dbName() const { return m_dbName; )
    void setDbName(const QString &name)
    private:
    QString m_dbName;
    @

    Then the setDbName is as follows:
    @
    void MyClass::setDbName(const QString &f)
    {
    if (f != m_dbName)
    {
    m_dbName = f;
    ui->databaseName->setHtml(m_dbName );
    }
    }
    @

    databaseName being the QTextBrowsers object name (set in the designer).

    I have the user clicking a button and opening a QFileDialog, using the return value I want to set m_dbName and thus have it updated in the QTextBrowser....

    Is this in any way the correct approach for having class members linked to widgets of that class...? Should I be using the NOTIFY along with a signal...? I know I can just call ui->databaseName->setHtml(m_dbName ) in the same method opening the file dialog and have it set... Should I even be trying this?

    I have other QStrings and widgets I wish to do the same: just set the value of the string (or whatever the variable is).

    Thanks again man... No one where I work has even touched Qt so having someone to ask a few questions is amazing...



  • If you need the wizard, wouldn't it be a good idea to use the QWizardPage::wizard method instead? It directly returns a QWizard*; no casting needed.

    Note that if you want to communicate values between the wizard and its pages or between pages, you can use the fields mechanism too.



  • Yea but I need a pointer to the actual class. I'm trying to reuse as much code as possible... and they create pointers to class instances, pass them around, and set members of these instances throughout the wizard. Like 250+ members across a 2 classes. I guess I could just make the pointers fields but meh...it's already working.

    Any input on the Q_PROPERY question I had...? :D


  • Lifetime Qt Champion

    Generally, if you have a property you want to propagate you use NOTIFY to make the signal name known to the property system (it also ensure that you don't forget to add the signal to your object).

    Then the classic applies:
    @
    void setMyProperty(const QString &propertyValue)
    {
    if (m_propertyValue != propertyValue) {
    m_propertyValue = propertyValue;
    emit propertyValueChanged(m_propertyValue)
    }
    }
    @

    Now if you use e.g. a QLineEdit (either in a ui file or directly in code) you don't need to store yourself the string since it's already done by the QLineEdit.

    You can then simplify your code:
    @
    MyCoolClass::MyCoolClass(QWidget *parent):
    QWidget(parent)
    {
    // ui setup et everything else
    connect(ui->myLineEdit, SIGNAL(textChanged(QString)), SIGNAL(myPropertyChanged(QString)));
    }
    void setMyProperty(const QString &propertyValue)
    {
    ui->myLineEdit->setText(propertyValue)
    }
    @


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.