Layout, widgets not inside ???
-
I thought I'd hit on something, I found another post online and added:
pobjLayout->addItem(new QWidgetItem(pobjWidget));
No joy, still doesn't work! Looking at the layout in the debugger, after executing this line, there are no additions to the children, same with addWidget...so what do I have to do?
-
Provide a minimal compilable example of that specific part of your code so that people can experiment with it.
-
@SGaist , this is difficult, but I will try:
This is the XML:
<groupbox id="enSEX" eol="true" align="left" layout="vertical" title="Radios" dbfield="vcSex" properties="QGroupBox { border-radius: 8px; background-color:#ff0000; }"> <radiobutton id="rdoM" text="Male" default="true" position="0,0"/> <radiobutton id="rdoF" text="Female" position="1,0"/> </groupbox>
I have quite a lot of code that parses all the various node types, here is the bit for the above:
if ( pobjParent != nullptr ) { //Does the parent have a layout? pobjLayout = pobjParent->pobjGetLayout(); if ( pobjLayout != nullptr ) { //Yes, clear the pobjParWidget widget pobjParWidget = nullptr; } } pobjWidget = qobject_cast<QWidget*>(clsCNT::pCreate(this, mstrName, strCSS, slstProperties, pobjParWidget));
The above code calls pCreate which based on the content of mstrName creates the widget:
QWidget* clsCNT::pCreate(clsXMLnode* pobjNode, const QString& crstrType ,QString& rstrCSS, QStringList& rslstProperties ,QWidget* pobjParent) { if ( clsCNT::blnValidType(crstrType) == true ) { if ( crstrType.compare(clsCNT::mscszButton) == 0 ) { return new clsQtPushBtn(pobjNode, &rstrCSS, pobjParent); } else if ( crstrType.compare(clsCNT::mscszCheckbox) == 0 ) { return new clsQtCheckBox(pobjNode, &rstrCSS, pobjParent); } else if ( crstrType.compare(clsCNT::mscszCombo) == 0 ) { return new clsQtComboBox(pobjNode, &rstrCSS, &rslstProperties, pobjParent); } else if( crstrType.compare(clsCNT::mscszFrame) == 0 ) { return new clsQtFrame(pobjNode, &rstrCSS, pobjParent); } else if ( crstrType.compare(clsCNT::mscszGroupBox) == 0 ) { return new clsQtGroupBox(pobjNode, &rstrCSS, &rslstProperties, pobjParent); } else if ( crstrType.compare(clsCNT::mscszLabel) == 0 ) { return new clsQtLabel(pobjNode, &rstrCSS, &rslstProperties, pobjParent); } else if ( crstrType.compare(clsCNT::mscszLineEdit) == 0 ) { return new clsQtLineEdit(pobjNode, &rstrCSS, &rslstProperties, pobjParent); } else if ( crstrType.compare(clsCNT::mscszListWidget) == 0 ) { return new clsQtListWidget(pobjNode, &rstrCSS, &rslstProperties, pobjParent); } else if ( crstrType.compare(clsCNT::mscszRadioButton) == 0 ) { return new clsQtRadioButton(pobjNode, &rstrCSS, pobjParent); } else if ( crstrType.compare(clsCNT::mscszSliderVert) == 0 ) { return new clsQtSlider(Qt::Vertical, pobjNode, &rstrCSS, pobjParent); } else if ( crstrType.compare(clsCNT::mscszSliderHorz) == 0 ) { return new clsQtSlider(Qt::Horizontal, pobjNode, &rstrCSS, pobjParent); } else if ( crstrType.compare(clsCNT::mscszSpinBox) == 0 ) { return new QSpinBox(pobjParent); } else if ( crstrType.compare(clsCNT::mscszTextEdit) == 0 ) { return new clsQtTextEdit(pobjNode, &rstrCSS, &rslstProperties, pobjParent); } } return nullptr; }
Give the widget a human readable name and add it to the layout if one exists:
if ( pobjWidget != nullptr ) { //Set the object name QString strID(strGetAttribute(clsXMLnode::mscszAttrID)), strName(mstrName); if ( strID.isEmpty() != true ) { strName += ", id: " + strID; } pobjWidget->setObjectName(strName); } if ( pobjLayout != nullptr ) { //Any alignment? QString strAlign(pobjParent->strGetAttribute(clsXMLnode::mscszAttrAlignment)); Qt::Alignment eCellAlign(Qt::AlignVCenter | Qt::AlignHCenter); if ( strAlign.compare(clsXMLnode::mscszGeomCenter) == 0 ) { eCellAlign |= Qt::AlignHCenter; } else if ( strAlign.compare(clsXMLnode::mscszGeomLeft) == 0 ) { eCellAlign |= Qt::AlignLeft; } else if ( strAlign.compare(clsXMLnode::mscszGeomRight) == 0 ) { eCellAlign |= Qt::AlignRight; } //Add the widget to the layout QLayoutItem* pobjItem(new QWidgetItem(pobjWidget)); pobjItem->setAlignment(eCellAlign); pobjLayout->addItem(pobjItem); // pobjLayout->addWidget(pobjWidget); }
Hopefully this is enough, however at this point I really don't think its something I've done wrong but a limitation or restriction in Qt, bearing in mind that my code does this all at run-time where as the UI create in Qt is parsed when the project is compiled.
[Edit], I just decided to debug again and single stepped into addItem, interesting:
void QBoxLayout::addItem(QLayoutItem *item) { Q_D(QBoxLayout); QBoxLayoutItem *it = new QBoxLayoutItem(item); d->list.append(it); invalidate(); }
When I get into addItem, on QBoxLayoutItem *it = new QBoxLayoutItem(item);:
If I click on Step Over twice, the cursor is pointing to invalidate();, the watch window has changed to:
Looks very wrong and after returning back to where the call took place there is no addition to the layout.
addWidget calls addItem internally, so if its a bug in addItem this explains everything.
[Edit 2] I have file a bug:
https://bugreports.qt.io/browse/QTBUG-97662 -
@SPlatten said in Layout, widgets not inside ???:
my code does this all at run-time where as the UI create in Qt is parsed when the project is compiled.
While Qt Designer's .ui files are parsed at compile time, the parser generates C++ code that runs at runtime.
You said that the WYSIWYG editor works. So, build a working GUI and then inspect the
ui_*.h
file that is generated in your build folder. Copy the code inside thesetupUi()
method. -
@JKSH , this is from the header file:
QGroupBox *groupBox; QWidget *verticalLayoutWidget; QVBoxLayout *verticalLayout; QRadioButton *Radio1; QRadioButton *Radio2; QRadioButton *Radio3;
Will take a good look, because the verticalLayoutWidget looks like its added by Qt Creator and is obviously required, and thats something thats missing in my code.
Then there is this code:
groupBox = new QGroupBox(centralWidget); groupBox->setObjectName(QString::fromUtf8("groupBox")); groupBox->setGeometry(QRect(120, 170, 301, 201)); verticalLayoutWidget = new QWidget(groupBox); verticalLayoutWidget->setObjectName(QString::fromUtf8("verticalLayoutWidget")); verticalLayoutWidget->setGeometry(QRect(9, 29, 291, 161)); verticalLayout = new QVBoxLayout(verticalLayoutWidget); verticalLayout->setSpacing(6); verticalLayout->setContentsMargins(11, 11, 11, 11); verticalLayout->setObjectName(QString::fromUtf8("verticalLayout")); verticalLayout->setContentsMargins(0, 0, 0, 0); Radio1 = new QRadioButton(verticalLayoutWidget); Radio1->setObjectName(QString::fromUtf8("Radio1")); verticalLayout->addWidget(Radio1); Radio2 = new QRadioButton(verticalLayoutWidget); Radio2->setObjectName(QString::fromUtf8("Radio2")); verticalLayout->addWidget(Radio2); Radio3 = new QRadioButton(verticalLayoutWidget); Radio3->setObjectName(QString::fromUtf8("Radio3")); verticalLayout->addWidget(Radio3);
Which clearly creates a new widget and positions it between QGroupBox and QVBoxLayout.
-
@SPlatten said in Layout, widgets not inside ???:
Which clearly creates a new widget and positions it between QGroupBox and QVBoxLayout.
What is for? The gaps between verticalLayoutWidget and groupBox can be handled with verticalLayout->setContentsMargins(11, 11, 11, 11); verticalLayoutWidget is not needed. Check the example in my link.
-
@JoeCFD , I think you misunderstand what I am saying. I used Qt Creator to build this example, I did the following:
- Dragged Group Box from Containers palette and dropped onto centralWidget
- Dragged Vertical Layout from Layouts palette and dropped onto Group Box
- Dragged Radio Button from Buttons palette and dropped onto Vertical Layout
- Dragged Radio Button from Buttons palette and dropped onto Vertical Layout
- Dragged Radio Button from Buttons palette and dropped onto Vertical Layout
- Edited text attribute for each control
I did not do anything to add the mysterious verticalLayoutWidget which was added by Qt Creator. I am saying this works and its only because Qt Creator is doing something else instead of adding a QGroupBox, QVBoxLayout and child widgets.
-
@SPlatten Nothing wrong with it. In your case, I think you do not need it. It is better to understand how this works. I did the same thing in my link with designer which does not have verticalLayoutWidget.
groupBox = new QGroupBox(centralwidget); groupBox->setObjectName(QString::fromUtf8("groupBox")); verticalLayout = new QVBoxLayout(groupBox); verticalLayout->setObjectName(QString::fromUtf8("verticalLayout")); radioButton = new QRadioButton(groupBox); radioButton->setObjectName(QString::fromUtf8("radioButton")); verticalLayout->addWidget(radioButton); radioButton_2 = new QRadioButton(groupBox); radioButton_2->setObjectName(QString::fromUtf8("radioButton_2")); verticalLayout->addWidget(radioButton_2); radioButton_3 = new QRadioButton(groupBox); radioButton_3->setObjectName(QString::fromUtf8("radioButton_3")); verticalLayout->addWidget(radioButton_3);
-
@SPlatten If verticalLayoutWidget does not exist, groupBox is a natural choice. You can set their parents to be central widget as well. It is layouts which hold and organize widgets. Children are cleared when their parents are destroyed.
Sometimes, I need to move a widget to another place in my app. What I do is to remove its parent first and add a new parent. Then add it to the layout of the new parent.
An overlaid widget is made within its parent widget without being placed in any layout. Sure an overlaid widget can have a layout. In your case, verticalLayoutWidget is an overlaid widget since it is not in any layout.
-
@SPlatten said in Layout, widgets not inside ???:
verticalLayoutWidget->setGeometry(QRect(9, 29, 291, 161))
your verticalLayoutWidget height is 161 and vertical margins of the layout are 11 * 2; The layout height for your radio buttons is 161 - 23 = 138 px. What is the height of your single radio button?
what is the central widget width and height?
groupBox->setGeometry(QRect(120, 170, 301, 201));
its width has at least 120 + 301 px. -
@SPlatten Here's my suggestion:
- Copy the working code from Qt Designer into a small test project. Build it and run it -- make sure the resulting GUI looks correct.
- Gradually modify the working code to become more and more like your own custom code. Rebuild and re-run it after each small modification -- make sure the resulting GUI still looks correct at each step.
- As soon as the GUI stops looking correct, investigate your latest modifications.
That will help you pinpoint exactly what's causing the GUI to look "not right".
-
@SPlatten in designer after you finish your layout, click form (between edit and view)->preview in->fusion style
to preview your layout. Then resize the display of main window or dialog or widget to see if they resize properly. If not, change your layout. -
@JoeCFD , No offence, I'm not sure you are reading or understanding what I'm trying to do. I have the everything in an XML file, when I read in the XML my code translates the XML at run-time into a GUI, I'm not using Qt Creator / Designer at all except for testing and feasibility testing.
There is some odd behaviour in what I'm trying to do and what Qt Creator does that as far as I can see isn't documented and seems to be additional glue.
-
@JKSH , I will try what you suggest, single stepping through my existing code this is what is done, using this XML:
<groupbox id="enSEX" eol="true" align="left" layout="vertical" title="Radios" dbfield="vcSex" properties="QGroupBox { border-radius: 8px; background-color:#ff0000; }"> <radiobutton id="rdoM" text="Male" default="true" position="0,0"/> <radiobutton id="rdoF" text="Female" position="1,0"/> </groupbox>
A node is created with a widget which I name with setObjectName to groupbox, id: enSEX, this node has a layout attribute so a layout QVBoxLayout is created:
... } else if ( strLayout.compare(clsXMLnode::mscszLayoutVertical) == 0 ) { mpobjLayout = new QVBoxLayout(mpobjWidget); strName = "QVBoxLayout"; } if ( strName.isEmpty() != true ) { mpobjLayout->setObjectName(strName + QString(", id: %1") .arg(strGetAttribute(clsXMLnode::mscszAttrID))); }
The first radio button is created as a child of QGroupBox, it has the object name radiobutton, id: rdoM, so far the debugger shows:
Then I carry on to the next radio button which has the object name radiobutton, id: rdoF, the result in the debugger doesn't look correct anymore and now shows:
Where has radiobutton, id: rdoM gone and the output is still wrong:
The radio buttons work correctly, the layout has the title and correct style but why or why do the radio buttons appear outside of the layout?