How to change QWizard default buttons in each QWizardPage
-
No one? :(( I'm still stuck there :(
-
What do you want to achieve with this code:
void BaseWizard::ChangeButtons() { QList<QWizard::WizardButton> button_layout; button_layout <<QWizard::Stretch << QWizard::CustomButton1 << QWizard::CustomButton2; }
You create a local variable button_layout which is destroyed when ChangeButtons() finishes!
Shouldn't you call setButtonLayout(button_layout):void BaseWizard::ChangeButtons() { QList<QWizard::WizardButton> button_layout; button_layout <<QWizard::Stretch << QWizard::CustomButton1 << QWizard::CustomButton2; setButtonLayout(button_layout) }
-
@jsulm O.o ermmmm... wow! yes, I used that function on the constructor the first time I create the buttons_layout but forgot it there in the function .... what a Stupid mistake... BUT now, putting it like you said it makes my program crashes.
QList<QWizard::WizardButton> button_layout; button_layout.clear(); qDebug() << " 1"; button_layout <<QWizard::Stretch << QWizard::CustomButton1 << QWizard::CustomButton2 << QWizard::NextButton << QWizard::FinishButton; qDebug() << " 2 "; setButtonLayout(button_layout); qDebug() << " 3";
If I run it with that code it prints
1 2
and then crashes in the setButtonLayout() function with a niceThe program has unexpectedly finished.
-
Can you post the stack trace?
-
BaseWizard *bz; bz->ChangeButtons();
Is this exactly how you use your wizard? If that's the case
bz
is just a wild pointer and doesn't actually reference any object. -
@jsulm said:
stack trace?
How can I get it?
@kshegunov Well I put the funcion on my BaseWizard and was trying to call it from a QWizardPage like that thinking it was correct... how should I do it instead?
-
You should get it if you execute your app from QtCreator and it crashes.
You did not initialize the pointer, so it is showing to nirvana:
BaseWizard *bz; bz->ChangeButtons();
-
@roseicollis
Well, you have to operate on an object. If the way shown is the exact excerpt of the code you'll always get a segmentation fault, because inChangeButtons()
you dereferencethis
by callingsetButtonLayout()
. You can use instead:BaseWizard * bz = dynamic_cast<BaseWizard *>(wizard());
or any other way that actually provides you with the valid wizard object.
Kind regards.
-
@jsulm Well in the Compile output it says that exit normally (if that is what you mean, if not, can you point me where can I find or see the stack trace?
@kshegunov said:
BaseWizard * bz = dynamic_cast<BaseWizard *>(wizard());
Annd.... DING DING DING! We have a winner here! Yes, this absollutely solves my problem. Thank you so much! I love a little with all that about casts... why can't you just do something like
BaseWizard *bz = new BaseWizard()
? why do you have to use a cast and moreover,dynamic_cast
? -
@roseicollis
Firstly you'll need the wizard your page belongs to, this is the one you're trying to modify, that's why I suggested using thewizard()
method. But that method (naturally) gives you a pointer to the base class (QWizard). Because you're trying to typecast a pointer down in the hierarchy and not up (which is always safe) your best bet is to do that withdynamic_cast
. This ensures that if the object you receive is not from that hierarchy branch, or you pass a NULL pointer as argument, or your object can't be cast downwards (meaning that it actually is a base class object), the cast will return NULL. This provides you with a safe way to cast object pointers. The most clean approach is to useqobject_cast
which works pretty much the same way, but for that you need your class to be declared as a metatype to Qt, which I was not sure you had done.Kind regards.
-
but for that you need your class to be declared as a metatype to Qt, which I was not sure you had done.
Neither do I :PWhat do you mean with metatype and how do you declare it? I just use to code making it works and if it does not, then I search on the internet and try to learn what it does but all that you mentioned its far away from my knowlegde...but I want to learn it all so that's why I ask it :) Thank you so much!
One more thing: I have my BaseWizard class like that:
#include "WPn"// include of all the wizardpages I have (in the .cpp) class BaseWizard : public QWizard
And the BasePAge like this:
#include "basewizard.h" //(in the .cpp) class BasePage : public QWizardPage
And every QWizardPage like this:
#include "basewizard.h" // in .cpp #include "basepage.h" // in .cpp class WP1 : public BasePage
So now I'm trying to call in basewizard's constructor a function from basepage, but still have the same problem and don't know how to do it really, I've tried with something like:
BasePage *bp = dynamic_cast<BasePage *>( new QWizardPage()); // really not sure how to writte it sorry) bp->SetSubTitleStyle();
I know that as basewizard is not including basepage it is not possible (and I can't include it because its BaseWizard the one included on BasePage. So...How could I do that?
I need that because when you use setStyleSheet() on QT, it keeps the last one, it doesn't merge them or something like that so I have a general css for labels set in BaseWizard and I want one label (common in all wp) to have another style. I've also tried putting the Wizard style on basepage instead of basewizard but then the program crashes.. I do it putting that in the constructor of basepage:
BaseWizard * bz = dynamic_cast<BaseWizard *>(wizard()); bz->setStyleSheet("QWizard{background-color: black);}" "QComboBox:focus, QLineEdit:focus{ background-color: #dddddd; }" "QPushButton{ font-weight: bold; }" "QPushButton:focus{background-color: #8888a8); color:orange;}" "QLabel{font-weight: bold;color:orange}"); SetSubTitleStyle(); //function that chagnes the common label css
-
@roseicollis said:
What do you mean with metatype and how do you declare it?
A meta-type is a class/type that is known to Qt's meta-object system. You're required to declare your class as a meta-type when you intent to use Qt's template functions that depend on it (these include QVariant's conversions and qobject_cast). You also need to register your class at runtime as a meta-type if it will be used as an argument for queued signal-slot connections, which is relevant to multithreaded applications.
On your other question:
BasePage *bp = dynamic_cast<BasePage *>( new QWizardPage()); // really not sure how to writte it sorry) bp->SetSubTitleStyle();
This is a bad idea, because of two things:
- Your wizard is managing your pages, but should not be required to know anything about how the pages are built or styled. This is a responsibility of your page, not your wizard.
- The code is simply wrong, from C++ point of view. You create an object of type
QWizardPage
, then you try to cast the pointer returned to a derived class pointer, which will always causedynamic_cast
to return NULL (simply becauseQWizardPage
is not aBasePage
). So at the end of the day, when you call your function, you'll just get a segmentation fault becausebp
is NULL.
Suppose you have the following hierarchy:
class A { }; class B : public A {}; class C : public A {}; class D : public B {};
This means
B
isA
,C
isA
,D
isB
(but becauseB
isA
,D
isA
as well). What you're trying to tell the compiler with your code is: "I have an object of typeA
and want to treat it (thedynamic_cast
) as an object of typeB
", but you see, this is not correct, because whileB
isA
,A
is notB
, so thedynamic_cast
will always return NULL (meaning it can't provide a meaningful conversion). Now suppose you have objects created like this:A * a = new A; // This is okay, our pointer references object of the same type A * b = new B; // This is okay as well, our pointer references an object of type B (but threats it as an object of type A). It's possible because B extends A. B * bb = new A; // Error! The object is of type A, and cannot be meaningfully accessed like it was of type B. B does not extend A, it's the other way around!
So...How could I do that?
You could set your style for the page in the page's constructor (not in the wizard's constructor).
I hope this helps.
Kind regards. -
@kshegunov Ohhh I see it now, I understand it so much better. Thank you for the explanation and the examples, they helped me a lot as they are easy to understand for me :). I know I can do it in every WP constructor but I wanted to avoid it as it mean I will have this line in every of my 50 wizardpages so that's why I was trying to set it in another way but seeing it is totally 'ilegal' then I'll do it this way.
Really greatfull for your reply! :D
-
@roseicollis
You're welcome.I know I can do it in every WP constructor but I wanted to avoid it as it mean I will have this line in every of my 50 wizardpages so that's why I was trying to set it in another way but seeing it is totally 'ilegal' then I'll do it this way.
Well this is exactly why you have a
BasePage
class, isn't it? You put all the common functionality inside your base class (this would be yourBasePage
constructor) and when a wizard page is supposed to do something different you derive from your BasePage a new type that will provide you with the new behavior. My point is that yourWizard
should not know about how the page is built or styled, but all the pages are of typeBasePage
, andBasePage
does and should handle all the common things related to the wizard pages, while the wizard itself just collects and displays the pages.Kind regards.
-
@kshegunov Yes yes I understand you and that was what I was trying to achieve but dunno why it didn't work fine. finally it works correctly without having to call it every time in every constructor of every wizardpage. The label that was not ok with the stylesheet had a QPalette with the colour and then some css with setStyleSheet() so seems that both are incompatibles and doing that the setStyleSheet() function was ignored. I've removed the QPalette and now it works perfect.
Thanks for everything!