PDA

View Full Version : Dynamically created buttons.



Tomasz
28th November 2010, 22:48
Hello!

I've got a problem with buttons and pointers. I need to create dynamically something like "array" of buttons on one of my application windows (each time the window opens). Now I've got some code:



QPushButton *btn[HOW_MANY_BUTTONS];

for(int j=0; j<HOW_MANY_BUTTONS; j++)
{
btn[j] = new QPushButton;
btn[j]->setGeometry(0,0,40,40);

ui->verticalLayout->addWidget(btn[j],Qt::AlignVCenter);
}


It works just fine. But number of buttons is changing, and I don't want to create array of pointers which is bigger or smaller than number of buttons. Any suggestions how should I write function which is creating as many buttons as I need in a moment?

thanks in advance
best regards
Tomasz

SixDegrees
28th November 2010, 22:54
Use a std::vector instead of a fixed-size array. Or, simply let the layout do the bookkeeping, including destruction.

Tomasz
29th November 2010, 00:23
Use a std::vector instead of a fixed-size array. Or, simply let the layout do the bookkeeping, including destruction.

I'll read about std::vector. But what about that layout? How should it work?

thanks in advance
best regards
Tomasz

Tomasz
29th November 2010, 09:15
I'm trying to use std::vector but, can I have pointers as elements of vector? How can add buttons to vector?

thanks in advance
best regards
Tomasz

wysota
29th November 2010, 09:23
QVector<QPushButton*> btn; // or std::vector

for(int j=0; j<HOW_MANY_BUTTONS; j++)
{
QPushButton *b = new QPushButton;
b->setGeometry(0,0,40,40);
ui->verticalLayout->addWidget(b,Qt::AlignVCenter);
btn << b;
}

BalaQT
29th November 2010, 09:58
hi ,
u can use QHash too.
i will use like this ,


QHash<int,QPushButton*> btn;

int HOW_MANY_BUTTONS=200; //u can change this value dynamically as u wish;
for(int j=0; j<HOW_MANY_BUTTONS; j++)
{
QPushButton *b=new QPushButton;
btn[j]=b;
b->setGeometry(0,0,40,40);
ui->verticalLayout->addWidget(b,Qt::AlignVCenter);
}

hope it helps

Bala

SixDegrees
29th November 2010, 10:59
Note also, in addition to the above, that a QLayout itself acts much like a vector: it has count(), addItem(), removeItem() and itemAt() functions that might serve just as well as using an external vector to keep track of the items managed by the layout. It isn't really possible to say whether this approach would work without knowing more about your application, but sometimes it allows you to use a single object - the layout - rather than two - the layout plus an external container.

Tomasz
29th November 2010, 11:28
QVector<QPushButton*> btn; // or std::vector

for(int j=0; j<HOW_MANY_BUTTONS; j++)
{
QPushButton *b = new QPushButton;
b->setGeometry(0,0,40,40);
ui->verticalLayout->addWidget(b,Qt::AlignVCenter);
btn << b;
}

So, if I want to clear that vector I can use:



btn.clear();


It will clear also verticalLayout?

thanks in advance
best regards
Tomasz

wysota
29th November 2010, 12:03
It will clear also verticalLayout?
No, it won't.

BalaQT
29th November 2010, 12:17
hi,

void QVector::clear ()
Removes all the elements from the vector and releases the memory used by the vector.

u need to remove the widgets from the layout.
use

void QLayout::removeWidget ( QWidget * widget )

hope it helps
Thnks
Bala

Tomasz
29th November 2010, 12:23
So, it is as I thought. But what if I do something like that:



QVector<QPushButton*> btn;

btn.clear();

for(int j=0; j<HOW_MANY_BUTTONS; j++)
{
QPushButton *b = new QPushButton;
b->setGeometry(0,0,40,40);
btn << b;
ui->verticalLayout->addWidget(btn[j],Qt::AlignVCenter);
}


Can I then remove item from layout using:



ui->verticalLayout->removeWidget(btn[i]);


Or maybe different pointer points on that widget?

thanks in advance
best regards
Tomasz

BalaQT
29th November 2010, 12:27
Can I then remove item from layout using ui->verticalLayout->removeWidget(btn[i]);

yes surely u can


Or maybe different pointer points on that widget?

no its the same pointer

hope it helps
Bala

Tomasz
29th November 2010, 12:32
But if I remove that widget from layout, pointer stays in vector? And I can use it again or just remove it from vector too?

thanks in advance
best regards
Tomasz

BalaQT
29th November 2010, 12:37
But if I remove that widget from layout, pointer stays in vector?

yes pointer stays in vector, since u didnt remove it from Vector.


And I can use it again

yes, surely u can use it again.


or just remove it from vector too?

if u dont want that widget then remove it from vector too..

layout and vector are different...

for ur understanding ... vector is holding the widget pointer.
that widget will be added to the layout by addWidget
and removed by removeWidget

hope it helps
Bala

Tomasz
29th November 2010, 14:22
One more question to end that thread. I've got my buttons, now I'm connecting them to QSignalMapper:



QVector<QPushButton*> btn;

btn.clear();

for(int j=0; j<HOW_MANY_BUTTONS; j++)
{
QPushButton *b = new QPushButton;
b->setGeometry(0,0,40,40);
btn << b;
ui->verticalLayout->addWidget(btn[j],Qt::AlignVCenter);
connect(btn[j], SIGNAL(clicked()), sigMap, SLOT(map()));
sigMap->setMapping(btn[j], j);
}

connect(sigMap, SIGNAL(mapped(int)), this, SLOT(func(int)));


What will now happen with QSignalMapper if I remove buttons from layout and vector? Should I clean somehow signal mapper? What happen with all connections?

thanks in advance
best regards
Tomasz

wysota
29th November 2010, 14:36
If you "remove" buttons from the layout and vector nothing will happen and connections to the mapper will still be maintained. But if you delete the buttons, all their connections will be broken.

From a technical point of view your vector doesn't hold buttons, it holds pointers to buttons. So you are not removing buttons from the vector (or the layout as a matter of fact) but pointers to buttons.

Tomasz
29th November 2010, 14:58
So the safest way to do the cleaning is to: remove widgets from layout, then DELETE all created buttons with:



delete(btn[x]); // btn is vector with pointers


and at the end - i can safely clear vector, and then connections will be broken, and QSignalMapper will be 'clean'? Yes? And then I can create everything again?

thanks in advance
best regards
Tomasz

wysota
29th November 2010, 15:01
It's enough to delete the buttons. They will be taken out of layouts.


qDeleteAll(btn);
btn.clear();

Tomasz
30th November 2010, 20:07
One more question - should I use disconnect() to disconnect all signals (from created buttons) from slots.

thanks in advance
best regards
Tomasz

wysota
30th November 2010, 23:05
One more question - should I use disconnect() to disconnect all signals (from created buttons) from slots.
Why don't you try it first with and without disconnecting and then answer your own question?

BalaQT
1st December 2010, 05:09
hi,

should I use disconnect() to disconnect all signals
u should disconnect all the buttons.
one button's disconnect will disconnect only that signal.

hope it helps
Bala

wysota
1st December 2010, 08:43
u should disconnect all the buttons.
one button's disconnect will disconnect only that signal.
I suggest you do that experiment as well, BalaQT.

BalaQT
1st December 2010, 09:42
hi wysota,
thnks fr ur reply

I suggest you do that experiment as well, BalaQT.

i tried and following are the outputs.
when i try

disconnect(btn[0],0,0,0); //disconnect single buttons
sigMap->disconnect(); //disconnect all signals from sigMap


@Tomasz: should I use disconnect() to disconnect all signals (from created buttons) from slots.

so to disconnect all signals , use sigMap->disconnect();

Bala

wysota
1st December 2010, 11:26
That was not the point. Delete all the objects and see if the connections are still valid.

BalaQT
1st December 2010, 11:48
That was not the point. Delete all the objects and see if the connections are still valid.

hi wysota,
i tried and when we delete all the objects, connections are also deleted.

Bala

Tomasz
2nd December 2010, 09:33
That was not the point. Delete all the objects and see if the connections are still valid.

You're right. Nice feature of qDeleteAll().

Thanks again!
best regards
Tomasz

wysota
2nd December 2010, 09:40
It's not a feature of qDeleteAll, when you delete a particular object, its connections are always broken. qDeleteAll is an equivalent of:

foreach(item *i, container){
delete i;
}