When are widgets deleted in Qt (QVBoxLayout class)? - c++

I have some simple code to create a new widget using Qt:
Dock::Dock() : QDockWidget() {
label = new QLabel(QLatin1String("TEST"));
QVBoxLayout* layout = new QVBoxLayout();
layout->addWidget(label, 0, Qt::AlignTop);
layout->addStretch(-1);
QWidget* multiWidget = new QWidget();
multiWidget->setLayout(layout);
setWidget(multiWidget);
}
Where label is a private member QLabel* label. My question is: am I responsible for deleting label in Dock's destructor?
I tried changing the code so that label is a std::shared_ptr<QLabel>:
Dock::Dock() : QDockWidget() {
label = std::make_shared<QLabel>(QLatin1String("TEST"));
QVBoxLayout* layout = new QVBoxLayout();
layout->addWidget(label.get(), 0, Qt::AlignTop);
layout->addStretch(-1);
QWidget* multiWidget = new QWidget();
multiWidget->setLayout(layout);
setWidget(multiWidget);
}
So that it is deleted automatically when `Dock' is destroyed but I get an error when I close the program.

In order to properly set up the objects tree you need to do the following:
Create the container widget first,
Create child widget and set it's parent,
Create layout of the container widget,
Add widget to the layout.
Here is the code that demonstrates the mentioned approach:
Dock::Dock()
:
QDockWidget()
{
QWidget* multiWidget = new QWidget;
label = new QLabel(QLatin1String("TEST"), multiWidget); // Set parent
QVBoxLayout* layout = new QVBoxLayout(multiWidget); // Sets layout
layout->addWidget(label, 0, Qt::AlignTop);
layout->addStretch(-1);
setWidget(multiWidget);
}

Related

I want to add a label in new widget using the Qt framework

This is my code :
void maquette::on_btn_edit_clicked()
{
QWidget* wdg = new QWidget;
wdg->resize(320, 340);
wdg->setWindowTitle("Modiffier");
QLabel label1("matricule", wdg);
label1.setGeometry(100, 100, 100, 100);
wdg->show();
}
the window shows up but the label didn't show
void maquette::on_btn_edit_clicked()
{
QWidget *wdg = new QWidget;
wdg->resize(320,340);
wdg->setWindowTitle("Modiffier");
QLabel *label1 = new QLabel("matricule",wdg);
label1->setGeometry(100, 100, 100, 100);
wdg->show();
}
You can either add the QLabel using parenting. as mentioned before.
QLabel *label1 = new QLabel("matricule",wdg);
or
QLabel *label1 = new QLabel("matricule");
label1->setParent(wdg);
This will make the widget float inside its parent.
You can also add the QLabel to a layout that has been assigned to the QWidget.
QVBoxLayout* layout = new QVBoxLayout();
wdg->setLayout(layout);
QLabel *label1 = new QLabel("matricule");
layout->addWidget(label1);
This will add the widget to the layout.
The layout will control how the child widgets are laid out.

How to manage layout on QDockWidget?

I'm getting started with Qt and I have a project for my school. I want to make an interface that read a database of space-stuff and displays them.
Until now I can display the table in a list, and my actual goal is to show the details of the object when it is double clicked.
To do so I tried to open a second dock whenever the object is double clicked, and tried to make a layout inside the second dock to display properly the details.
The program successfuly open a new dock, but the widget are way too small and all packed in the upper left corner of the dock:
picture of the bug:
I tried to do not use layout but only setWidget with QDockWidget, but it does only display the last widget.
Here is my code for the layout:
dock1 = new QDockWidget(tr("Caractéristiques de l'objet : "), this);
dock1->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
QVBoxLayout* layout = new QVBoxLayout();
Nom_Objets = new QLineEdit(dock1);
layout->addWidget(Nom_Objets);
//dock1->setWidget(Nom_Objets);
Categorie_Objets = new QLineEdit(dock1);
layout->addWidget(Categorie_Objets);
//dock1->setWidget(Categorie_Objets);
Description_Objets = new QTextEdit(dock1);
layout->addWidget(Description_Objets);
//dock1->setWidget(Description_Objets);
setLayout(layout);
addDockWidget(Qt::RightDockWidgetArea, dock1);
If you want to add several widgets to a QDockWidget then you must use a QWidget as a container:
dock1 = new QDockWidget(tr("Caractéristiques de l'objet : "), this);
dock1->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
addDockWidget(Qt::RightDockWidgetArea, dock1);
QWidget* container = new QWidget;
dock1->setWidget(container);
QVBoxLayout* layout = new QVBoxLayout(container);
Nom_Objets = new QLineEdit;
Categorie_Objets = new QLineEdit;
Description_Objets = new QTextEdit;
layout->addWidget(Nom_Objets);
layout->addWidget(Categorie_Objets);
layout->addWidget(Description_Objets);

Qt layouts, difference between passing and not passing QWidget as parent

I have created a simple QHBoxLayout (horizontal) that is pushed to the bottom of the QVBoxLayout (Vertical) and it contains two buttons. See code:
QWidget* create_ver_and_horizontal_box() {
QWidget* temp = new QWidget();
// Add buttons to the horizontal box
QHBoxLayout* hbox = new QHBoxLayout();
QPushButton *ok = new QPushButton("OK");
QPushButton *cancel = new QPushButton("Cancel");
hbox->addWidget(ok);
hbox->addWidget(cancel);
// Create a vertical box and add the horizontal box to
// the end of it
QVBoxLayout* vbox = new QVBoxLayout();
vbox->addStretch(1);
vbox->addLayout(hbox);
// set the layout and return
temp->setLayout(vbox);
return temp;
}
and the resulting UI is the following.
But when I add the QWidget temp to be the parent of the QHBoxLayout, like so:
// Add buttons to the horizontal box
QHBoxLayout* hbox = new QHBoxLayout(temp);
This is what I get:
I want to understand what is going on here. And in which cases I want the QWidget to be the parent of a layout or any other QWidget(s) and in which cases I don't the containing QWidget to be the parent of the containing QWidgets. For example, I could've added temp to be the parent of the two Push buttons but I didn't. What is the implication of not adding vs adding.
Thanks,
QHBoxLayout* hbox = new QHBoxLayout(temp);
is equivalent to
QHBoxLayout* hbox = new QHBoxLayout();
temp->setLayout(hbox);
I.e. you are making the horizontal layout responsible for temp.
The call to setLayout(vbox) should have generated a runtime warning message, that temp already has a layout, hinting at that.
Since you want the vertical layout to be responsible for that widget, either keep the temp->setLayout(vbox) or pass temp to the constructor of QVBoxLayout.

Center children widget in parent widget(parent widget was added in layout)

I created a layout contain a parent widget. In that parent widget i created another widget.
My code is similarly to this:
QGridLayout *layout = new QGridLayout();
QWidget *parentWidget = new QWidget();
layout->addWidget(parentWidget );
QWidget *childWidget = new QWidget(parentWidget);
How can i center the child widget in parent widget ?
The problem is we cannot get the true size of parent widget because it's in a layout.
Move the child inside the parent's showeEvent. You can use a bool flag to do it only when the parent is shown for the first time.
void Parent::showEvent(QShowEvent *)
{
if(_first_show)
{
_first_show = false;
_child->move(this->rect().center() - _child->rect().center());
}
}
Proof that it works (red is the parent, and blue is the child):
You can do this by setting fixed size of child widget and placing it inside grid layout of parent widget.
QGridLayout *layout = new QGridLayout();
QWidget *parentWidget = new QWidget();
layout->addWidget(parentWidget );
QWidget *childWidget = new QWidget(parentWidget);
QGridLayout *parentLayout = new QGridLayout();
parentWidget->setLayout(parentLayout);
parentLayout->addWidget(childWidget);
childWidget->setFixedSize(/*some fixed size for child widget*/);

Items in QHBoxLayout layout overlap

I can't figure out what is wrong with Qt. I am trying to create a simple layout, like this:
+-------+-----------+
| | Label1 |
| Thumb |-----------+
| | Label2 |
| |(multiline)|
+-------+-----------+
And this is the code that does this:
labelInfoName = new QLabel("Sample name", this);
labelInfoDetails = new QLabel("Sample details...", this);
labelInfoDetails->setAlignment(static_cast<Qt::Alignment>(Qt::AlignTop | Qt::AlignLeft));
QVBoxLayout* textInfoLayout = new QVBoxLayout(this);
textInfoLayout->addWidget(labelInfoName);
textInfoLayout->addWidget(labelInfoDetails, 1);
// Create info pane
imgInfoThumbnail = new QLabel(this);
imgInfoThumbnail->setFixedSize(64, 64);
imgInfoThumbnail->setStyleSheet("background: black;");
QHBoxLayout* infoLayout = new QHBoxLayout(this);
infoLayout->addWidget(imgInfoThumbnail);
infoLayout->addLayout(textInfoLayout, 1)
this->setLayout(infoLayout);
And this is a QWidget. This is the code that sets up the layout in a class derived from QWidget. Then I want to display it as a dockable widget, which I do like this from my QMainWindow class:
widget = new Widget(this); // Widget that was set up above
QDockWidget* dockWidget = new QDockWidget("Project", this);
dockWidget->setWidget(widget);
addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
But this is what I get instead:
I need the widget to be a custom control that I can place anywhere. Previously, it was defined as a QDockWidget, and instead of calling this->setLayout() I was creating a QWidget object, and this worked as expected:
QWidget* widget = new QWidget(this);
widget->setLayout(infoLayout);
this->setWidget(widget);
But the way I've done it now, it puts them on top of each other. What am I doing wrong?
You are creating layout incorrectly.
When you pass parent (widget) to a layout this layout is set automatically as layout to this widget.
Problem is that once layout is set for a widget it can't be changed, I'm pretty sure you are receiving some warning about this.
So just remove this when constructing a layout (at least in first case):
labelInfoName = new QLabel("Sample name", this);
labelInfoDetails = new QLabel("Sample details...", this);
labelInfoDetails->setAlignment(static_cast<Qt::Alignment>(Qt::AlignTop | Qt::AlignLeft));
QVBoxLayout* textInfoLayout = new QVBoxLayout();
textInfoLayout->addWidget(labelInfoName);
textInfoLayout->addWidget(labelInfoDetails, 1);
// Create info pane
imgInfoThumbnail = new QLabel(this);
imgInfoThumbnail->setFixedSize(64, 64);
imgInfoThumbnail->setStyleSheet("background: black;");
QHBoxLayout* infoLayout = new QHBoxLayout(this);
infoLayout->addWidget(imgInfoThumbnail);
infoLayout->addLayout(textInfoLayout, 1)
this->setLayout(infoLayout);