[SOLVED] Accessing a parent widget's variables
-
That was actually my first idea, but I wasn't sure if it is 100% OK to pass a QObject derived class instead of QObject for parent. Just tested it, it seems to work fine. Not that it is a waste to learn how to use qobject_cast ;) Note, this is only possible in the constructor, outside of it the parent() method will still return a QObject pointer unless you overload the method, or easier - just cast the pointer as mentioned above.
-
bq. bq. Well, obviously you need a pointer to your parent object, not to QObject which is passed in the constructor
Oh, of course! That "Qwidget * Parent" line is so common I never stopped to think about what it. Ok, so this leaves me with two questions:
-
How does the parent() function differ from simply using (or casting) the parent pointer? As I pointed out earlier, I get very different errors for each of these.
-
Whether I modify the constructor or use a cast, I have to refer to the parent class by name within the child class. Since the parent class already includes the child's header, how do I avoid the circularity of including the parent's header within the child? (I realize this is a C++ issue rather than Qt)
-
-
Use forward declaration - in the header declare your class, but don't #include its header:
@class YourParentClass;@
And that's all you will need in the header, forward declaration is a promise to the compiler that you will define YourParentClass later on. This is used to avoid circular dependencies and the associated object redefinition compiler errors. The actual header for your class you include in the cpp file instead.
The parent() method by default returns a QObject pointer, which is the lowest compatible facility, the bottom level base class. Your class inherits QObject, either directly or through QWidget, so if you need to access your custom members, you have to do a cast of that QObject pointer to your class type. Parent() will always return a QObject pointer, unless you overload the method yourself. This is not the case with passing a QObject pointer or a pointer to a QObject derived class in the constructor as a parameter, thus in the constructor you can avoid using the parent() method and casting it to your class and instead use pointer to your class directly, it can still be a parent since it "contains" a QObject inside of it. One of the errors you got is you passed your QObject as a copy and not as a pointer, since the -> syntax only works with pointers. Another error you might get is when you try to pass a QObject or derived class as a copy, QObject is by design non-copyable, the constructor is explicit to make sure it does not end up being used as a copy constructor.
-
bq. How does the parent() function differ from simply using (or casting) the parent pointer?
ddriver covered the basics, but I wanted to point out that the "parent" pointer that's in the constructor is arbitrarily named, and as such, may be adding to the confusion on what the details are. Just be aware that parent() is a method that is always named parent() and that the "parent" pointer could just as easily be named anything, like:
@
MyClass::MyClass(QObject *somethingElse) ...
@ -
Ah yes, parent() is a method that exists in the body of the class, the pointer, passed into the constructor exists only in the body of the constructor, and parent is just the logical identifier/name for the object, you can use whatever name you want.
The parent() method and the parent constructor local have nothing to do with each other. I didn't realize there was any confusion about it :)
I might add:
@MyClass::MyClass(AnyQObjectDerivedClass *somethingElse) {
somethingElse->someVariable...@ -
bq. Use forward declaration – in the header declare your class, but don’t #include its header:
Yes, I've tried a couple different forward declarations, but I can't get rid of the following errors:
invalid use of incomplete type 'struct ParentClass'
forward declaration of 'struct ParentClass'Incidentally, the child class now includes the line
@tempVar = qobject_cast<YourParentClass *>(parent());@
where tempVar is of type YourParentClass *.
bq. parent is just the logical identifier/name for the object, you can use whatever name you want[...]I didn’t realize there was any confusion about it
I'm afraid I'm now even more confused! :) If "Parent" is an arbitrary name, how would Qt decide what the parent of a given widget is if I passed more than one QObject pointer?
-
In your QObject-derived class, you pass a pointer to a parent object, then it's up to you to pass that pointer's value back to your superclass. This functionality is basic C++ Inheritance stuff and not unique to Qt, though it does apply heavily to Qt.
@
MyQObjectClass : public QObject
{
Q_OBJECT
public:
MyQObjectClass(QObject *theparent = 0);
...
}// In the constructor, you call QObject's constructor and pass the parent value upstream.
// This is how QObject knows what the parent is.
MyQObjectClass::MyQObjectClass(QObject *theparent) : QObject(theparent)
{
...
// parent() now returns whatever value was passed to the QObject upstream, since
// the parent() method originates back up the inheritance tree at the QObject level.
}
@ -
bq. invalid use of incomplete type ‘struct ParentClass’
forward declaration of ‘struct ParentClass’You forget to include the header of "ParentClass" in the *.cpp files which using the class.
By the way, Qt is a library of C++, make sure that you have mastered the basis of C++.
-
[quote author="planarian" date="1332957173"]
I'm afraid I'm now even more confused! :) If "Parent" is an arbitrary name, how would Qt decide what the parent of a given widget is if I passed more than one QObject pointer?[/quote]
Consider this, names a.k.a identifies MEAN NOTHING at runtime, those are just for the human who writes/reads the code. The compiler uses identifies to get the address of that object in memory, and knowing the type, the entire "topology" of the object in memory is known.
Since you inherit QObject, with inheritance, in the constructor you initialize the base class object as well, as mlong's code snippet indicates. So no matter how many QObject pointers you pass in the constructor of your object, it is the one pointer you use to initialize QObject with that becomes the parent. The reason you might have missed this is Qt Creator automatically initializes QObject when you create a new class inheriting QObject through the new class wizard.
This is not even Qt, this is general C++, as 1+1=2 suggested you should spend some time mastering C++, and Qt will suddenly make more sense :)
-
bq. it is the one pointer you use to initialize QObject with that becomes the parent
That's the source of my confusion: I simply didn't realize that QObject can never take more than one pointer.
bq. You forget to include the header of “ParentClass” in the *.cpp files which using the class.[...]make sure that you have mastered the basis of C++.
As it currently stands, parent.h includes child.h, parent.cpp includes parent.h, child.h has a "class parent" forward declaration, and child.cpp includes child.h. So I don't believe your diagnosis is correct.
My knowledge of C++ is not so remedial as I may have given the impression, but you are right to suppose that it isn't second nature to me, and your impatience is understandable. I appreciate everyone's time, and will try hard to ensure that any future posts are "on topic."
-
[quote author="planarian" date="1332968041"]
That's the source of my confusion: I simply didn't realize that QObject can never take more than one pointer.As it currently stands, parent.h includes child.h, parent.cpp includes parent.h, child.h has a "class parent" forward declaration, and child.cpp includes child.h. So I don't believe your diagnosis is correct. [/quote]
It is YOU (or eventually Creator) that constructs a QObject inside the QObject derived class, if inheritance is indirect the previous base class is responsble for it, and the parent pointer is passed down the hierarchy until it reaches the bottom base QObject class. Unlike with signals and slots, there is no magic here, no code is generated for you behind the scenes. QObject itself has only 3 constructors, and neither of them can take more than one parent parameter, and the parent parameter is not automatically passed into QObject, it is done in the constructor of the first class that inherits QObject by code, no matter how deep it is before your own class.
Your forward declaration should work the way you have described your situation. Either that is not the case, or there is some other issue, you are best posting your code and the exact error message that goes with it, so we can see what you are trying to do and if necessary test it ourselves. For me accessing parent members from a child totally works.
@// parent header
#ifndef MYPARENT_H
#define MYPARENT_H#include <QObject>
class MyParent : public QObject
{
Q_OBJECT
public:
explicit MyParent(QObject *parent = 0);
int someVariable;
};
#endif // MYPARENT_H// parent cpp
#include "myclass.h"MyParent::MyParent(QObject *parent) :
QObject(parent), someVariable(7) {} // some variable initialized to 7// child header
#ifndef MYCHILD_H
#define MYCHILD_H#include <QObject>
class MyParent; //forward declarationclass MyChild : public QObject
{
Q_OBJECT
public:
explicit MyChild(MyParent *parent = 0);
};
#endif // MYCHILD_H// child cpp
// parent header included here in the child cpp
#include "mychild.h"
#include "myparent.h"MyChild::MyChild(MyParent *parent) :
QObject(parent)
{
parent->someVariable = 666; // access parent member through pointer and change from 7 to 666
}//main
#include <QtCore/QCoreApplication>
#include <QDebug>
#include "myparent.h"
#include "mychild.h"int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);MyParent parent; qDebug() << parent.someVariable; // prints out 7 MyChild child(&parent); qDebug() << parent.someVariable; // prints out 666 qDebug() << dynamic_cast <MyParent *>(child.parent())->someVariable; // casting the QObject * to MyParent * using C++ dynamic cast, no checking, will crash if cast fails, prints out 666 MyParent * temp = qobject_cast <MyParent *>(child.parent()); //create a local pointer to parent from casting child parent() method with Qt qobject cast if (temp) { //check if cast succeeded temp->someVariable = 333; qDebug() << parent.someVariable; // prints out 333 } return a.exec();
}@
-
bq. You forget to include the header of “ParentClass” in the *.cpp files which using the class.
@1+1=2: I'm embarrassed to say that you were dead on after all. The one declaration I was missing was #include "parent.h" in child.cpp but due to my inexperience with forwarding declarations I didn't spot that I hadn't covered all the bases.
@ddriver: Once again you've written a ton of code for my benefit, and although I would have taken a lot longer to figure out this problem without your example, I still feel badly about it. If I lived in Bulgaria, I'd bring a cake to your office, or something....
bq. Unlike with signals and slots, there is no magic here, no code is generated for you behind the scenes.
I see now that moc has spooked me: I've had an unconscious tendency to assume that anything in Qt I don't immediately recognize is a mysterious extension of the language. This thread has done a great deal to clarify my understanding of Qt's boundaries, which is actually more valuable to me than the solution to any particular problem.
Thanks very much!
-
[quote author="planarian" date="1333043253"]
@ddriver: Once again you've written a ton of code for my benefit, and although I would have taken a lot longer to figure out this problem without your example, I still feel badly about it. If I lived in Bulgaria, I'd bring a cake to your office, or something....
[/quote]Well, I am new to programming myself, and that code I did for your sake as much as I did for myself, what a better way to improve than doing so helping others, besides that "ton" of code took only a few minutes, thanks to Qt Creator. So no need to feel bad, or of a cake for that matter, besides I don't eat sweet stuff, it is decremental in far too many ways :P
Don't forget to mark the thread with [SOLVED] once it has ran its course.
-
Very nice! This example works like a charm and has saved me a lot of head aches. Thank you!
-
Thank you so much . Your answer helped me fix my problem which I was stuck for almost a week. big thank again.