[Solved] Dynamically change (via code) the properties of various widgets created on Designer
-
What type of properties are you trying to change? There's a chance that there might be an easier way to approach it even beyond what you've proposed here.
-
[quote author="mlong" date="1334094350"]What type of properties are you trying to change? There's a chance that there might be an easier way to approach it even beyond what you've proposed here.
[/quote]
Hi mlong,
Basically i want to change the icon (image) of some of those buttons.
I'm changing them with
@ui->button3->setIcon(icon1);@But i think it's not something i'll achieve just on Designer (on Disabled Off, Disabled On, Active Off, Active On, etc) 'cause i have some rules for changing these icons. That's why i want to do this by code (rules like "timers" or "the order that the user pressed each button", etc.
-
I'm still not sure what you're trying to accomplish. By using
@
ui->button1->...
@
or whatever to reference your widgets you do have access to your items in code and can do whatever you'd like.If you're saying you'd like an array of widgets to work with, the easiest thing might be to have
@
QList<QPushButton *> m_buttonlist;...
m_buttonlist.append(ui->button0);
m_buttonlist.append(ui->button1);
...
m_buttonlist.append(ui->buttonN);
@
and then you can reference an individual button with
@
m_buttonlist[idx]->whatever();
@If you're trying to avoid the 1-time manual setup of that array, you could use something like this (I think) to automate it:
@
for (int idx = 0; idx < numbuttons; idx++) {
QString name = QString("button%1").arg(idx);
QPushButton * button = ui->findChild<QPushButton>(name);
if (button) {
m_buttonlist.append(button);
}
}
@
(brain to terminal.. consult your friendly "docs":http://qt-project.org/doc/qt-4.8/qobject.html#findChild for exact details on how to do this). -
You can try this:
@
QObjectList childrens = this->children(); // this is a widget which use your ui file
foreach( QObject* obj, childrens )
{
QPushButton* button = qobject_cast< QPushButton* >( obj );
if( button )
{
// action on button
}
}
@ -
Or, you do:
@
QList<QPushButton*> buttons = findChildren<QPushButton*>();
foreach { QPushButton * button, buttons) {
// action on button
}
@Slightly shorter than Hostel's version above :-)
If you want, you can restrict such a list to buttons marked from designer, by setting a custom dynamic property, and checking for that property in the loop above. Of course, you can combine this idea with mlongs's suggestion of builiding up a list of widgets, and then using that list. I would not use the button name for this though.
-
Thanks to all!
Yesterday i was using the first approach from mlong just to create and test the list of widgets - to see if i'd be able to manipulate them easily... and it worked.
Now to automate it i'm using Andre's version... one thing is that i didn't wanted every button to be added to that list - just some of them. So i've try to "set a custom dynamic property" and "check for that property in the loop" as suggested, and it worked.
Actually, i didn't SET any different property - i've just used the actual width of the button:
@QList<QPushButton*> buttons = findChildren<QPushButton*>();
foreach ( QPushButton * button, buttons) {
if(button->width()==20)
m_buttonlist.append(button);
}@And this works for me.. now, i don't know if any of you guys would suggest the use of another property for this check, for some reason. If that's the case, please - let me know!
Thanks again!
=====
Actually, i've noticed a little "problem" now. My QList is reversed (at least to what i'd expected).
(button32,button31,button30,button29, ... , etc, button1, button0)What can i do to re-reverse this? Some extra configuration in the loop, or it is easier to just reverse the QList somehow?
-
Why does the order of the list matter?
There is no way to control the order in which findChildren will return its results. Because the contents of the list are pointers, just sorting is useless as well. Note that even sorting on button name will result in a different order than you want, as button10 would be sorted before button2.
I would not abuse another property for identification purposes. It makes the feature hard to track, and easy to break. How will somebody else working on your code know that the width is relevant in some other way than just the width? What if you decide to change your layout a bit? Or what if the users style forces a larger or smaller button?
-
Yes, that crossed my mind.. that's why i asked if anyone could suggest another way or property to this. I have 42 buttons on my interface, and i want to create a QList with just 32 (the smaller, 20-width ones). The current solution works, but it is certainly not optimal.
And why does the order of the list matter... correct me if i'm wrong, but i'll access the items of that list by index. That's what i did with the first solution
@QList<QPushButton *> m_buttonlist;
...
m_buttonlist.append(ui->button0);
m_buttonlist.append(ui->button1);
...
m_buttonlist.append(ui->buttonN);@and, of course, it worked. I was just changing to this new version to clean it up a bit my code... maybe the "manual version" is, in the end, optimal for my needs?
[quote author="Andre" date="1334152754"]Why does the order of the list matter?
There is no way to control the order in which findChildren will return its results. Because the contents of the list are pointers, just sorting is useless as well. Note that even sorting on button name will result in a different order than you want, as button10 would be sorted before button2.
I would not abuse another property for identification purposes. It makes the feature hard to track, and easy to break. How will somebody else working on your code know that the width is relevant in some other way than just the width? What if you decide to change your layout a bit? Or what if the users style forces a larger or smaller button? [/quote]
-
The manual version of adding the controls to a list certainly is a serious option. It gives you full control over the order of the list, and it really isn't that much work. A bit of copy/pasting and a little editing does the trick. Note that you can also use the << operator on the list for a shorter notation:
Instead of
@QList<QPushButton *> m_buttonlist;...
m_buttonlist.append(ui->button0);
m_buttonlist.append(ui->button1);
...
m_buttonlist.append(ui->buttonN);@
you can write
@QList<QPushButton *> m_buttonlist;...
m_buttonlist << ui->button0
<< ui->button1
//...
<< ui->buttonN;
@I was wondering what the order of the items in the list matters for, yes. Of course you'll use the index to get to the pointer, but the question is if you need to do something different based on what button you are addressing. So far, nothing you said indicated that that was the case. If it is, then of course, the index matters.
-
Hi Andre,
Thanks for your help and explanations. I'll stick to the manual version then, using the << operator as you suggested. With this i'll even avoid that "width check" that was troubling me too.
It is wonderful to have support from guys like you here,
Thanks -
Glad you've found a solution that works for you. Just goes to show that there often a number of different ways to accomplish something, and you just have to judge the best option that works for you.
As an aside, I hope that you're not needing the array of buttons to help track which buttons were clicked, etc. If so, you may also want to look into "QSignalMapper":/doc/qt-4.8/qsignalmapper.html to help handle some of that work more efficiently.
-
Even for setting up a QSignalHandler, an array like the one constructed in this topic will be very useful :-)
-
bq. Even for setting up a QSignalHandler, an array like the one constructed in this topic will be very useful :-)
Indeed, but trying to do signal handling manually can be a bear. Just saying that if he needed to take that additional step, then the QSignalHandler could be a potential help.