Qt remove nested layout - c++

I've got several QHBoxLayout objects nested inside a single QVBoxLayout. I've looked through a number of stackoverflow questions and answers, but I've not been able to find a way to completely remove the layout for the contents of the QScrollArea widget. All the answers I've seen have only made it possible to set the layout again, but when the layout does get set a second time, the objects are still present.
This is the code that I'm working with:
QSignalMapper* sMap = new QSignalMapper(this);
QVBoxLayout* vBox = new QVBoxLayout();
outerVector = 0;
for (vector<vector<QPushButton*>>::iterator o_iter = buttonGrid.begin(); o_iter < buttonGrid.end(); o_iter++) {
int innerVector = 0;
QHBoxLayout* hBox = new QHBoxLayout();
for (vector<QPushButton*>::iterator i_iter = (*o_iter).begin(); i_iter < (*o_iter).end(); i_iter++) {
hBox->addWidget(buttonGrid.at(outerVector).at(innerVector));
sMap->setMapping(buttonGrid.at(outerVector).at(innerVector), ((outerVector * 100) + innerVector));
connect(buttonGrid.at(outerVector).at(innerVector), SIGNAL(clicked()), sMap, SLOT(map()));
innerVector++;
}
vBox->addLayout(hBox);
outerVector++;
}
ui->GameAreaWidgetContents->setLayout(vBox);
connect(sMap, SIGNAL(mapped(int)), this, SLOT(on_buttonGrid_clicked(int)));
Right now, I have this for clearing the layout:
delete hBox;
delete vBox;
ui->GameAreaWidgetContents->layout();
What is the best, and most effective way to clear the contents of the widget?

I believe I've fixed this, This is less of a Qt issue, but more of a lack of clearing the vector<vector<QPushButton*>> buttonGrid object. It looked like the layout wasn't being cleared, because the additional QPushButton objects were being added onto the vector<vector<QPushButton*>> object.
It's a fairly rookie mistake on my behalf.

Updated:
I infer that GameAreaWidgetContents is a QScrollArea. To clear its layout manager, you can do:
delete ui->GameAreaWidgetContents->layout();
The vbox will no longer be the widget's layout manager and any nested children will be deleted automatically by the Qt parenting system.
From the docs on QWidget::setLayout():
If there already is a layout manager installed on this widget, QWidget won't let you install another. You must first delete the existing layout manager (returned by layout()) before you can call setLayout() with the new layout.

Related

Scroll Area Added and Set Up but No Scrollbar Appears

I've seen and tried various QT scrollArea solutions over the past 2 days but none of them work for me. Here's my scroll area setup code as it stands in the MainWindow constructor. This builds and runs without error but doesn't do anything. The scrollArea and ui->Contents have already been set up in the form using QTcreator and the needed widgets have been moved into the scrollArea.
ui->scrollArea->installEventFilter(this);
ui->scrollArea->setMouseTracking(true);
ui->scrollArea->setWidget(ui->Contents);
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setSizeConstraint(QLayout::SetMinimumSize);
ui->scrollArea->setLayout(layout);
The last line seems interchangeable with:
layout->addWidget(ui->scrollArea)
but neither one changes the result, which is a fully-functioning application but without the scroll area I need.
I had similar problem which i solved by creating scrollArea and it's contents via code rather than form and only then using setWidget() method. I described the problem in this thread.
In your case code should look something like this:
QScrollArea *scrollArea;
scrollArea = new QScrollArea(this);
scrollArea->installEventFilter(this);
scrollArea->setMouseTracking(true);
scrollArea->setWidget(Contents);//whatever Contents is, i recommend creating it via code
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setSizeConstraint(QLayout::SetMinimumSize);
scrollArea->setLayout(layout);

Replace a widget in Qt

I have a base class which has some gui items that i have set positions of using the designer in Qt creator. Those items are:
QWidget* w1;
QWidget* w2;
QWidget* w3;
Now in a class that inherits that base class, I would like to "transform" those widgets into lineEdit items, that would keep all the geometrical parameters of that widgets. So I do something like this:
QLineEdit* leAmplitude;
leAmplitude = new QLineEdit(ui->w1);
leAmplitude->setGeometry(ui->w1->geometry());
ui->glControls->addWidget(leAmplitude);
But the added QLineEdit item doesn't appear in the exact same place as w1 item. Its just added at the bottom of other controls in the QGridLayout glControls. How to make the lineEdit to take all geometric parameters from w1?
Layout takes care of the widgets placed in the layout, according to the hints given by the widget, so calling setGeometry, then doing addLayout is not useful. Also, adding widget to layout resets it parent, so you setting new widget's parent to ui->w1 is not useful either.
Fortunately, there is QLayout::replaceWidget method! Just use that. Example:
QLineEdit* leAmplitude;
leAmplitude = new QLineEdit;
QLayoutItem *previous = ui->glControls->replaceWidget(ui->w1, leAmplitude);
// possibly assert that previous is ui->w1, or just delete it, or whatever
This method was added as late as in Qt 5.2 it seems, so if you need to support older versions, I can expand this answer to cover how to (try to) do the same manually. But in short, you have to use the right QGridLayout::addWidget overload and make sure relevant properties (including at least sizeHint and sizePolicy) match.
try this, it is works:
QLineEdit* leAmplitude;
leAmplitude = new QLineEdit(ui->w1->parentWidget());
ui->w1->parentWidget()->layout()->replaceWidget(ui->w1, leAmplitude);
ui->w1 = leAmplitude;

How to logically group widgets in QT for easy show/hide?

I'm grouping a set of widgets in a parent and then I control the visibility/flow of these widgets by hiding/showing the parent. Is this a good way to achieve what I'm trying to do? Here is the code:
QVBoxLayout* l = new QVBoxLayout(this);
// .....
QWidget* toolset_frame = new QWidget(this);
{
QVBoxLayout* l = new QVBoxLayout(toolset_frame);
l->addWidget(new QLabel(tr("Stuff")));
this->Toolset = new QLineEdit(toolset_frame);
l->addWidget(this->Toolset);
}
l->addWidget(toolset_frame);
// Call toolset_frame->hide() and this hides everything inside the parent
The problem with this solution is that the children shrink in size slightly, I think this is due to some padding or border in the parent. Ideally the children should appear as if they are not contained in an intermediate object, but rather flow with the parent. In this case the horizontal size of the children should not be affected.
http://doc.qt.io/qt-5/qtwidgets-dialogs-extension-example.html
This example shows that your approach is correct. Using a widget to contain the elements you want to hide, and so on.
If you want the margins/content margins/padding to be less, then change it.
// in finddialog.cpp
extensionLayout->setMargin(0);
To quickly prototype what properties to change to get it to look right, try laying it out in the Qt Designer, and modify the property editor to get the look and feel you want.
Hope that helps.

Qt : Qlabel and QPushButton in a QVBoxLayout

I have an issue, when I'm trying to add a QLabel and a QPushbutton object into a QVBoxLayout. The problem is, that it adds too much space between them like in the picture
Here is a code example of creating the layouts and the labels, and adding them. I'm adding the buttons later on, but that is just with another ->addWidget(button).
jobbcimke= new QLabel(trUtf8("Jobb oldal"));
jobbkozepcimke= new QLabel(trUtf8("Jobb part"));
balcimke= new QLabel(trUtf8("Bal oldal"));
balkozepcimke=new QLabel(trUtf8("Bal part"));
jobbfelulet=new QVBoxLayout();
jobbkozepfelulet=new QVBoxLayout();
balkozepfelulet=new QVBoxLayout();
balfelulet=new QVBoxLayout();
osszefogo=new QHBoxLayout();
jobbfelulet->setAlignment(Qt::AlignRight);
jobbkozepfelulet->setAlignment(Qt::AlignRight);
balfelulet->setAlignment(Qt::AlignLeft);
balkozepfelulet->setAlignment(Qt::AlignLeft);
balfelulet->addWidget(balcimke);
balkozepfelulet->addWidget(balkozepcimke);
jobbfelulet->addWidget(jobbcimke);
jobbkozepfelulet->addWidget(jobbkozepcimke);
osszefogo->addLayout(balfelulet);
osszefogo->addLayout(balkozepfelulet);
osszefogo->addLayout(jobbkozepfelulet);
osszefogo->addLayout(jobbfelulet);
setLayout(osszefogo);
How could I remove the space between them, or is there a better method to do this? I've created the labels for the layout size allocation.
If you dig into the documentation there's a setSpacing(int x) method for QLayouts that allows you to edit the spacing in between the elements, you may also need to add some QSpacerItems to get the positioning exactly where you want it, or apply constraints with the setGeometry(QRect rect) method.

Deleting widget that is in layout

What will happen if we will run delete widget for widget that is in layout? If this case was written in documentation, please give me the link (I didn't find).
Code example:
QLabel *l1 = new QLabel("1st");
QLabel *l2 = new QLabel("2nd");
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(l1);
layout->addWidget(l2);
QWidget *mainWidget = new QWidget;
mainWidget->setLayout(layout);
mainWidget->show();
delete l1;
l2->deleteLater();
Can things that will happen be different for l1 and l2?
I believe what you are doing is almost same, though neither would properly remove from layout the way you should be doing it. They are still being left as bad references in the layout (if I remember correctly)
The first one simply deletes the item now. The second will delete it once the control returns back to the event loop. But really, the way people usually remove items from a layout is to take them from the layout (giving it a chance to adjust itself), then delete the item and its widget (if you want).
QLayoutItem *child;
while ((child = layout->takeAt(0)) != 0) {
delete child->widget();
delete child;
}
Again, the deleting of the widget (child->widget()) is only needed if you want to destroy the widget that was added, in addition to the layout item that was holding it.
QLayout's listen for events of type ChildRemoved and remove the items
accordingly. Simply deleting the widget is safe.
by #FrankOsterfeld here.
dont use delete l1 on Qobjects that has active slots connected to them, you will run into a crash.
Use:
l1->hide();
l1->deleteLater();
It works fine for me
Generally, I don't like to delete Qt widgets, rather remove them from the appropriate layout. (Qt will delete its own widgets if you set the Delete on close window attribute. ) The difference between calling delete and delete later is that delete is the normal C++ delete operation that will call the destructor and free the memory associated with the object.
The deleteLater() method, as discussed in the Qt documentation deletes the object when the event loop is entered.