April 10, 2012

fredlord fredlord
Lab Rat
7 posts

[Solved] Dynamically change (via code) the properties of various widgets created on Designer

 

I’ve used Design to create my interface – it was easy and optimal for me (i’m a begginer at Qt and the interface is a little complex)

So, i know that i can get a reference to any widget created on Design by using i.e. ui->nameOfObject->pos();

But is there a way to dynamically change the properties of various widgtes by code? Let’s say i have 10 buttons, with the name’s being: button1, button2, button3, button4, etc.

Can’t i just use something like

  1. for(int i=0;i<=10;i++) {
  2. pos[i] = ui->"button"+i->pos.x
  3. }

Or the one and only way is by hard-coding each ui at one time?

  1. pos[0] = ui->button1->pos.x;
  2. pos[1] = ui->button2->pos.x;
  3. pos[2] = ui->button3->pos.x;

The above method “works” but anyone can see that this is not optimal at all. Of course the method with the for loop won’t work the way i posted it. Its just a “pseudo-code” to try to translate what i am hoping to achieve…

PS: In my actual code i have 32 buttons, not only 10….. And i want to change the icon of each one back and forth according to some rules…

Any help will be appreciated

13 replies

April 10, 2012

mlong mlong
Robot Herder
1551 posts

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.

 Signature 

Senior Software Engineer
AccuWeather Enterprise Solutions
/* My views and opinions do not necessarily reflect those of my employer.  Void where prohibited. */

April 11, 2012

fredlord fredlord
Lab Rat
7 posts

mlong wrote:
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.

Hi mlong,

Basically i want to change the icon (image) of some of those buttons.
I’m changing them with

  1. 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.

April 11, 2012

mlong mlong
Robot Herder
1551 posts

I’m still not sure what you’re trying to accomplish. By using

  1.  
  2. 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

  1. QList<QPushButton *> m_buttonlist;
  2.  
  3. ...
  4.  
  5. m_buttonlist.append(ui->button0);
  6. m_buttonlist.append(ui->button1);
  7. ...
  8. m_buttonlist.append(ui->buttonN);

and then you can reference an individual button with
  1. 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:

  1. for (int idx = 0; idx < numbuttons; idx++) {
  2.    QString name = QString("button%1").arg(idx);
  3.    QPushButton * button = ui->findChild<QPushButton>(name);
  4.    if (button) {
  5.       m_buttonlist.append(button);
  6.    }
  7. }

(brain to terminal.. consult your friendly docs [qt-project.org] for exact details on how to do this).

 Signature 

Senior Software Engineer
AccuWeather Enterprise Solutions
/* My views and opinions do not necessarily reflect those of my employer.  Void where prohibited. */

April 11, 2012

Hostel Hostel
Lab Rat
188 posts

You can try this:

  1.     QObjectList childrens = this->children(); // this is a widget which use your ui file
  2.     foreach( QObject* obj, childrens )
  3.     {
  4.         QPushButton* button = qobject_cast< QPushButton* >( obj );
  5.         if( button )
  6.         {
  7.                // action on button
  8.         }
  9.     }

April 11, 2012

Andre Andre
Robot Herder
6295 posts

Or, you do:

  1. QList<QPushButton*> buttons = findChildren<QPushButton*>();
  2. foreach { QPushButton * button, buttons) {
  3.    // action on button
  4. }

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.

 Signature 

Looking for Qt developers to join our team @ i-Optics: https://qt-project.org/forums/viewthread/25393/

April 11, 2012

fredlord fredlord
Lab Rat
7 posts

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:

  1. QList<QPushButton*> buttons = findChildren<QPushButton*>();
  2.         foreach ( QPushButton * button, buttons) {
  3.             if(button->width()==20)
  4.                 m_buttonlist.append(button);
  5.         }

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?

April 11, 2012

Andre Andre
Robot Herder
6295 posts

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?

 Signature 

Looking for Qt developers to join our team @ i-Optics: https://qt-project.org/forums/viewthread/25393/

April 11, 2012

fredlord fredlord
Lab Rat
7 posts

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

  1. QList<QPushButton *> m_buttonlist;
  2.  
  3. ...
  4.  
  5. m_buttonlist.append(ui->button0);
  6. m_buttonlist.append(ui->button1);
  7. ...
  8. 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?

Andre wrote:
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?

April 11, 2012

Andre Andre
Robot Herder
6295 posts

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

  1. QList<QPushButton *> m_buttonlist;
  2.  
  3. ...
  4.  
  5. m_buttonlist.append(ui->button0);
  6. m_buttonlist.append(ui->button1);
  7. ...
  8. m_buttonlist.append(ui->buttonN);

you can write
  1. QList<QPushButton *> m_buttonlist;
  2.  
  3. ...
  4.  
  5. m_buttonlist << ui->button0
  6.              << ui->button1
  7. //...
  8.              << 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.

 Signature 

Looking for Qt developers to join our team @ i-Optics: https://qt-project.org/forums/viewthread/25393/

April 11, 2012

fredlord fredlord
Lab Rat
7 posts

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

April 11, 2012

mlong mlong
Robot Herder
1551 posts

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 to help handle some of that work more efficiently.

 Signature 

Senior Software Engineer
AccuWeather Enterprise Solutions
/* My views and opinions do not necessarily reflect those of my employer.  Void where prohibited. */

April 11, 2012

Andre Andre
Robot Herder
6295 posts

Even for setting up a QSignalHandler, an array like the one constructed in this topic will be very useful :-)

 Signature 

Looking for Qt developers to join our team @ i-Optics: https://qt-project.org/forums/viewthread/25393/

April 11, 2012

mlong mlong
Robot Herder
1551 posts

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.

 Signature 

Senior Software Engineer
AccuWeather Enterprise Solutions
/* My views and opinions do not necessarily reflect those of my employer.  Void where prohibited. */

 
  ‹‹ [Solved]QGLWidget to QMainWindow      Inspecting a qvariantlist in qml ››

You must log in to post a reply. Not a member yet? Register here!