Custom widget using and extending Qt's pImpl
-
Currently I'm building a custom widget that should extend a given
QWidgetclass.I want to use Qt's pImpl and tried to make use of
Q_D,Q_Q,Q_DECLARE_PRIVATEand other macros.Since I don't have full access to Qt's private/internal stuff, I can not do it like it's done in the Qt source. There, the
WidgetPrivatepart inherits from e.g.QPushButtonPrivate,QSpinBoxPrivateor whatever widget the base class is, which my class can't (or better shouldn't, I believe).The macros above expand successfully, but there is still something missing, because of no
WidgetPrivate/QObjectPrivateinheritance.
If I create my own, e.g.QScopedPointer<QMyClassPrivate> const d_ptrpointer, I get warnings that I'm shadowing the originald_ptrdue to myQObjectinheritance (well, through the widget, which I want to extend).Should I suppress and ignore these warnings?
Are there any (working and good design) templates for this?
I found this one and built my widget upon this and by looking at the Qt source how it's done there, but it still doesn't feel like a clean solution (warnings etc...).
The example template also produces warnings, btw.Is there a recommended way of doing this?
Or shouldn't it be done like this at all?I feel a bit lost :-P
Any help appreciated :) -
Currently I'm building a custom widget that should extend a given
QWidgetclass.I want to use Qt's pImpl and tried to make use of
Q_D,Q_Q,Q_DECLARE_PRIVATEand other macros.Since I don't have full access to Qt's private/internal stuff, I can not do it like it's done in the Qt source. There, the
WidgetPrivatepart inherits from e.g.QPushButtonPrivate,QSpinBoxPrivateor whatever widget the base class is, which my class can't (or better shouldn't, I believe).The macros above expand successfully, but there is still something missing, because of no
WidgetPrivate/QObjectPrivateinheritance.
If I create my own, e.g.QScopedPointer<QMyClassPrivate> const d_ptrpointer, I get warnings that I'm shadowing the originald_ptrdue to myQObjectinheritance (well, through the widget, which I want to extend).Should I suppress and ignore these warnings?
Are there any (working and good design) templates for this?
I found this one and built my widget upon this and by looking at the Qt source how it's done there, but it still doesn't feel like a clean solution (warnings etc...).
The example template also produces warnings, btw.Is there a recommended way of doing this?
Or shouldn't it be done like this at all?I feel a bit lost :-P
Any help appreciated :)Hi,
On which platform are you getting that warning ? I just tested with 6.6.0 on macOS and it went fine without warning.
-
Hi,
On which platform are you getting that warning ? I just tested with 6.6.0 on macOS and it went fine without warning.
5.15 on Windows 10.
If I remove the
d_ptrfrom my class, it still compiles, the warnings go away but of course I have no pointer to my private widget data class.
But still can access usingQ_D(myClass)andd_func()...
which will sooner or later crash :o)While looking for some in-depth information I came across
One section says:
Inheriting d-pointers for optimization
In the above code, creating a single Label results in the memory allocation for LabelPrivate and WidgetPrivate. If we were to employ this strategy for Qt, the situation becomes quite worse for classes like QListWidget - it is 6 levels deep in the class inheritance hierarchy and it would result in upto 6 memory allocations!
This is solved by having an inheritance hierarchy for our private classes and having the class getting instantiated pass on a the d-pointer all the way up.
Notice that when inheriting d-pointers, the declaration of the private class has to be in a separate file, for example widget_p.h. It's no longer possible to declare it in the widget.cpp file.The example then shows two classes,
LabelandWidget(not evenQWidget), whereLabelinherits the latter.
Same with their private classes:class LabelPrivate : public WidgetPrivate Label::Label() : Widget(*new LabelPrivate) // initialize the d-pointer with our own Private { } Label::Label(LabelPrivate &d) : Widget(d) { }I understand the benefits, but this will never work, when you have a
QObject-based class, because you can neither pass your ownd_ptr"upwards" the tree, since your own private class doesn't inherit fromQWidgetPrivate(and furtherQObjectPrivate), so the argument is not accepted due to wrong type, nor use the existing one, right?!That's what I am asking myself the whole time... how to adapt to the
QObject-tree to create a fully functionalQWidgetwhile having your own implementation, that extends some existingQWidget-class [ * ]?You cant? Or am I missing something?!
[ * ]: And with
QWidgetI meanQSpinBox,QPushButtonetc, not the actual plainQWidget, but this shouldn't make any difference, as they are allQWidgets, just one or two level(s) down the tree :-) -
5.15 on Windows 10.
If I remove the
d_ptrfrom my class, it still compiles, the warnings go away but of course I have no pointer to my private widget data class.
But still can access usingQ_D(myClass)andd_func()...
which will sooner or later crash :o)While looking for some in-depth information I came across
One section says:
Inheriting d-pointers for optimization
In the above code, creating a single Label results in the memory allocation for LabelPrivate and WidgetPrivate. If we were to employ this strategy for Qt, the situation becomes quite worse for classes like QListWidget - it is 6 levels deep in the class inheritance hierarchy and it would result in upto 6 memory allocations!
This is solved by having an inheritance hierarchy for our private classes and having the class getting instantiated pass on a the d-pointer all the way up.
Notice that when inheriting d-pointers, the declaration of the private class has to be in a separate file, for example widget_p.h. It's no longer possible to declare it in the widget.cpp file.The example then shows two classes,
LabelandWidget(not evenQWidget), whereLabelinherits the latter.
Same with their private classes:class LabelPrivate : public WidgetPrivate Label::Label() : Widget(*new LabelPrivate) // initialize the d-pointer with our own Private { } Label::Label(LabelPrivate &d) : Widget(d) { }I understand the benefits, but this will never work, when you have a
QObject-based class, because you can neither pass your ownd_ptr"upwards" the tree, since your own private class doesn't inherit fromQWidgetPrivate(and furtherQObjectPrivate), so the argument is not accepted due to wrong type, nor use the existing one, right?!That's what I am asking myself the whole time... how to adapt to the
QObject-tree to create a fully functionalQWidgetwhile having your own implementation, that extends some existingQWidget-class [ * ]?You cant? Or am I missing something?!
[ * ]: And with
QWidgetI meanQSpinBox,QPushButtonetc, not the actual plainQWidget, but this shouldn't make any difference, as they are allQWidgets, just one or two level(s) down the tree :-)You can extend a QWidget but must do this without accessing the d pointer of the widget as it is not visible outside of QtWidgets library.
-
You can extend a QWidget but must do this without accessing the d pointer of the widget as it is not visible outside of QtWidgets library.
@Christian-Ehrlicher said in Custom widget using and extending Qt's pImpl:
You can extend a QWidget but must do this without accessing the d pointer of the widget as it is not visible outside of QtWidgets library
So I should have my own
d_ptrfor my custom implementation, while keeping the inherited stuff untouched?
Found out there isQ_DECLARE_PRIVATE_D(myDptr, Class)which declares thed_func()and everything else using the first argument, you pass to that macro.
Then I have my own d-pointer, named different thand_ptr, which doesn't collide with the inherited, originald_ptrfromQObjectand there I'm not shadowing it anymore.
It was just about the naming?!
Is this the way? :)Will try and see how it goes... thx @Christian-Ehrlicher , @SGaist
-
@Christian-Ehrlicher said in Custom widget using and extending Qt's pImpl:
You can extend a QWidget but must do this without accessing the d pointer of the widget as it is not visible outside of QtWidgets library
So I should have my own
d_ptrfor my custom implementation, while keeping the inherited stuff untouched?
Found out there isQ_DECLARE_PRIVATE_D(myDptr, Class)which declares thed_func()and everything else using the first argument, you pass to that macro.
Then I have my own d-pointer, named different thand_ptr, which doesn't collide with the inherited, originald_ptrfromQObjectand there I'm not shadowing it anymore.
It was just about the naming?!
Is this the way? :)Will try and see how it goes... thx @Christian-Ehrlicher , @SGaist
@Pl45m4 said in Custom widget using and extending Qt's pImpl:
It was just about the naming?!
Is this the way? :)I would say yes.
-
P Pl45m4 has marked this topic as solved on