Finding QGridLayout elements in Qt - qt

I created labels and added them to the layout. How to get the elements from the layout? I tried to use method children(), but it gives empty list... Is there a way to get them? Some sample code below.
QGridLayout* layout = new QGridLayout();
QLabel* test = new QLabel();
test->setPixmap(m_staticStorage->getFirstImg());
test->setScaledContents(true);
QLabel* test2 = new QLabel();
test2->setMaximumSize(50,50);
test2->setPixmap(m_staticStorage->getSecondImg());
tes2->setScaledContents(true);
layout->addWidget(worker, 0, 0);
layout->addWidget(farmer, 0, 1);
ui->verticalLayout->addLayout(layout);
//layout->children() ->>>> empty

This will iterate over any QLayout subclass to find the items which have been added so far:
for (int i=0; i < layout->count(); ++i) {
QLayoutItem *item = layout->itemAt(i);
if (!item || !item->widget())
continue;
QLabel *label = qobject_cast<QLabel*>(item->widget());
if (label) {
// .... do stuff with label
}
}
One can also iterate in a similar fashion over each row or column of a QGridLayout using QGridLayout::columnCount() or QGridLayout::rowCount() and then QGridLayout::itemAtPosition() to get the actual QLayoutItem.
If you need to uniquely identify the QLabel after finding it, you could for example give each label a unique objectName or do a setProperty() on them with a unique ID when creating them.
QLabel *test1 = new QLabel(this);
test1->setObjectName(QStringLiteral("test1"));
....
if (label) {
if (!label->objectName().compare(QLatin1String("test1")))
// this is "test1" label
}
QLabel *test1 = new QLabel(this);
test1->setProperty("id", 1);
....
if (label) {
if (label->property("id").toInt() == 1)
// this is "test1" label
}

Better to use the function QObject::findChild
Qt is returning all children of a given Type and Objectname. You can decide to get only direct children or also all recursively.
this->findChild<QLabel*>(QString(), Qt::FindDirectChildrenOnly);
This will return all direct children of this (where this is your parent widget, not your layout) with any name and of type QLabel*
Your approach do not work because the layout do not take the ownership of the labels:
From Layout Management:
Tips for Using Layouts
When you use a layout, you do not need to pass a parent when
constructing the child widgets. The layout will automatically
reparent the widgets (using QWidget::setParent()) so that they are
children of the widget on which the layout is installed.
Note: Widgets in a layout are children of the widget on which the
layout is installed, not of the layout itself. Widgets can only have
other widgets as parent, not layouts.
You can nest layouts using addLayout() on a layout; the inner layout
then becomes a child of the layout it is inserted into.
BTW: Don't forget to set a parent for your layout
QGridLayout* layout = new QGridLayout(this);
and for your labels too
QLabel* test2 = new QLabel(this);

Related

How to autofit widget size and position to a cell in QTreeWidget?

I pragrammaticaly create a QTreeWidget.
Then I pragrammaticaly add some items.
Then I add two QLabel widgets to two items (QTreeWidgetItem) by
myTree->setItemWidget(item1, 0, myLabel1);
myTree->setItemWidget(item2, 0, myLabel2);
And then I try to resize the row of the item pragrammaticaly.
If I use an
item1->setSizeHint(0, QSize(myWidth, myHeight) );
the row chaged. But myLabel1 is not.
If I use an
item1->setSizeHint(0, QSize(myWidth, myHeight) );
myLabel->resize(myWidth, myHeight);
everething is ok but the row of myLabel2 mis adjusting to label by position.
Can I do something to auto-adjusting a widget (by size and position) to a cell of QTreeWidget?
P.S. After any resizing of tree (resize by width or expand/collapse node) widgets updates correctly.
In view of the fact that autofit start after resizing QTreeWidget, there is some method inside that resize widgets in cells.
So I opened QTreeWidget description (https://doc.qt.io/qt-5/qtreewidget.html) and red all of Public Functions and Public Slots. When I did not find any useful function I looked at a parent class (QTreeView). And found
myTree->resizeColumnToContent(0);
Call resizeColumnToContent after resizing any row in a QTreeWidget and widgets will be always fit to cells.
P.S. I am the OP.
you can try adding/updating a widget as an item, for example:
QWidget* wdg = new QWidget;
QPushButton* btIcon = new QPushButton();
QLabel* lb = new QLabel();
QHBoxLayout* layout = new QHBoxLayout(wdg);
layout->addWidget(btIcon);
layout->addWidget(lb);
layout->setAlignment( Qt::AlignCenter );
wdg->setLayout(layout);
myTree->setItemWidget(item1, 0, wdg);
Or just fill the tree with widgets

QT. Add new layout to QLayout

I create interface dynamically when Application is run.
1) I have QTabWidget with 4 predefined tabs. But i must show only 1 or 2 tabs, in case of user shoice. On StackOverflow i learned, that i must keep all tabs in collection to add and destroit it.
I have QHash: twInputMethodsTabs = new QHash< int, QPair<QWidget*, QString> >();
First argument = index; Second = Tab Widget; Third = Tab Widget Caption Text;
2) I fill the collection like this:
for(int i = 0; i < ui->twInputMethods->children().length(); i++)
{
twInputMethodsTabs->insert(i, QPair<QWidget*, QString>(ui->twInputMethods->widget(i), ui->twInputMethods->tabText(i)));
}
3) I add new widget in the tab like this:
twInputMethodsTabs->value(1).first->layout()->addWidget(cmbbCommands);
4) How can i add new layout to this widget? I want to do like this:
QHBoxLayout *hblParams =new QHBoxLayout();
twInputMethodsTabs->value(1).first->layout()->addLayout(hblParams);
But it does not work, because layout() returns QLayout which havent addLayout() function. How i can do this?
Or how can i should change architecture of code to do this?
In this following code you get a widget (.first) and then select that widget's layout ->layout() and then add a Widget to that layout ->addWidget().
twInputMethodsTabs->value(1).first->layout()->addWidget(cmbbCommands);
In the following code you get a widget (.first) and then select that widget's layout ->layout() and try to set the layout on the layout.
twInputMethodsTabs->value(1).first->layout()->addLayout(hblParams);
Replacing the QLayout
To set the layout on the parent widget, you need to drop the ->layout():
twInputMethodsTabs->value(1).first->addLayout(hblParams);
Note that since you are now adding an empty layout to the widget, any widgets current in the previous layout will be lost, so you may need to re-add the widgets to the layout.
Adding new QLayout inside existing QLayout
If you want to add a layout into the existing layout, you cannot do this directly. QLayout can only accept QWidget via .addWidget(). However, you can apply a layout to an empty QWidget() and then add that to the layout. For example:
QWidget *w = new QWidget();
w.addLayout(hblParams);
twInputMethodsTabs->value(1).first->layout()->addWidget(w);
An alternative is to set the layout on the QWidget to a layout that does support .addLayout() such as QHBoxLayout or QVBoxLayout. For example:
QVBoxLayout *l = new QVBoxLayout();
cmbbCommands.setLayout(l); // Now has a layout that supports .addLayout
twInputMethodsTabs->value(1).first->layout()->addWidget(cmbbCommands);
Now the following should work because ->layout() returns a QVBoxLayout:
QHBoxLayout *hblParams =new QHBoxLayout();
twInputMethodsTabs->value(1).first->layout()->addLayout(hblParams);
I Hope, I get what you want to do:
twInputMethodsTabs->value(1).first->layout()->addWidget(cmbbCommands);
QHBoxLayout *hblParams =new QHBoxLayout();
QWidget *w = new QWidget(twInputMethodsTabs->value(1).first);
twInputMethodsTabs->value(1).first->layout()->addWidget(w);
w->addLayout(hblParams);
I just wrote the code here, so it is untested. However it should give you an idea what I tried to explain in my comment.
Cutted from "working" application:
WidgetA::WidgetA(QWidget *parent) : QWidget(parent)
{
QVBoxLayout *pLayout = new QVBoxLayout();
buildWidget(pLayout);
this->setLayout(pLayout);
}
void WidgetA::buildWidget(QVBoxLayout *layout){
for(int i=0; i<4; ++i){
this->buildSegments(layout);
}
}
void WidgetA::buildSegments(QVBoxLayout *layout){
QHBoxLayout *pHbl = new QHBoxLayout();
QLabel *pSegmentSize = new QLabel(this);
pSegmentSize->setText(tr("Segment Size(1,N)"));
QSpinBox *pSegments = new QSpinBox(this);
pHbl->addWidget(pSegmentSize);
pHbl->addWidget(pSegments);
layout->addItem(pHbl);
}
Read this one: Widgets Tutorial - Nested Layouts

Small panel at the bottom of a QTreeWidget

I'm using QT 5.4.2 and trying to create a small panel at the bottom
of a subclassed QTreeWidget.
Here is the code:
void HmiScenarioAutoscriptPanel::searchEmitter() {
QWidget *child = new QWidget(ui->emitterTreeWidget);
//QMainWindow* child = new QMainWindow;
QLabel *labelSearch = new QLabel("Search");
QLineEdit *lineSearch = new QLineEdit();
lineSearch->setFixedSize(100, 20);
QHBoxLayout* layout = new QHBoxLayout(ui->emitterTreeWidget);
layout->setAlignment(Qt::AlignBottom);
layout->addWidget(child);
layout->addWidget(labelSearch);
layout->addWidget(lineSearch);
}
The label and search field correctly appear at the bottom of the tree,
however the fields overlap with the tree nodes (see image below).
Any idea why this behavior?
Ciao
Alf
enter image description here
It is not recommended to set layout on the tree widget. It is like other controls like a button, label etc..
I see that you are using designer. Add a blank widget (searchWidget) under the tree widget and then
void HmiScenarioAutoscriptPanel::searchEmitter() {
QWidget *child = new QWidget(ui->searchWidget);
//QMainWindow* child = new QMainWindow;
QLabel *labelSearch = new QLabel("Search", searchWidget);
QLineEdit *lineSearch = new QLineEdit(searchWidget);
lineSearch->setFixedSize(100, 20);
QHBoxLayout* layout = new QHBoxLayout(ui->searchWidget);
layout->setAlignment(Qt::AlignBottom);
layout->addWidget(child);
layout->addWidget(labelSearch);
layout->addWidget(lineSearch);
}
Just out of curiosity, why don't you add these using the designer as well?

Drawing lines and checkbox on same layer in Qt

I want to design a GUI using Qt. That contains lines and check-boxs, which are connected to each other like this :
----------[ ]-----------
------[ ]---------[ ]-------------
(where dash represents line and [] is for check-box)
Lines are created dynamically. And selecting the check-box will disable the corresponding line. So basically the lines and check-box should be on same layer.
Any hint/link about the implementation is appreciated.
You'll need a combination of QFrame, QCheckBox, and QHBoxLayout. For something a little fancier, you could sub-class your own QWidget for each section and add them incrementally to a QVBoxLayout. Something like this...
class CheckLine : public QWidget
{
Q_OBJECT
public:
CheckLine(int numboxes = 1, QObject* parent = 0) :
QWidget(parent)
{
m_layout = new QHBoxLayout;
m_layout->setSpacing(0); //you can also set the margins to zero if need be
setLayout(m_layout);
QFrame* firstline = new QFrame();
firstline->setFrameShape(QFrame::HLine);
m_layout->addWidget(firstline);
m_lines.append(firstline);
for(int i = 0; i < numboxes; ++i)
addBox();
}
void addBox()
{
QCheckBox* newbox = new QCheckBox(""); //add text here - or leave it blank if you want no label
m_newbox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
m_layout->addWidget(newbox);
m_boxes.append(newbox);
QFrame* newline = new QFrame();
newline->setFrameShape(QFrame::HLine);
m_layout->addWidget(newline);
m_lines.append(newline);
/* link each checkbox to disable the line after it */
connect(newbox, SIGNAL(toggled(bool)), newline, SLOT(setEnabled(bool)));
// connect(newbox, SIGNAL(toggled(bool)), this, SLOT(setEnabled(bool))); //use this instead if you want it to disable the entire row
}
private:
QHBoxLayout* m_layout;
QList<QCheckBox*> m_boxes;
QList<QFrame*> m_lines;
};
Then, create a widget with a QVBoxLayout and new a CheckLine, incrementing numboxes by 1 each time. Tweak the code if you want any checkbox to disable the entire line.

Qt: "Expanding" doesn't work inside a layout

My purpose is to create a scrollable control with a QVBoxLayout inside of it that has various controls (say buttons) on it. That control is put on a *.ui form. In the constructor for that control I write the following code:
MyScrollArea::MyScrollArea(QWidget *parent) :
QScrollArea(parent)
{
// create the scrollable container
this->container = new QWidget(); // container widget member
this->container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
this->container->setContentsMargins(QMargins(0,0,0,0));
this->content = new QVBoxLayout(); // layout member
this->content->setMargin(0);
this->content->setSpacing(0);
for (int i=0; i<100; i++)
{
QPushButton * widget = new QPushButton();
widget->setText("button");
widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
this->content->addWidget(widget);
}
this->container->setLayout(this->content);
this->content->layout();
this->setWidget(this->container);
}
My problem: the buttons have a fixed size and do not expand horizontally. they have a fixed size. i'd like them to expand horizontally to fill the row they're in. How can I get them expanding horizontally across their parent container?
Try calling this->setWidgetResizable(true);

Resources