Adding QScrollArea to layout locks application.
-
I have written a simple test application:
#include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , mpButtonGroupA(nullptr) , mpButtonGroupB(nullptr) , mpFormLayoutA(nullptr) , mpFormLayoutB(nullptr) , mpsaA(nullptr) , mpsaB(nullptr) , ui(new Ui::MainWindow) { ui->setupUi(this); int intFixedHeight(fontMetrics().height() * 3); QVBoxLayout* pvbxLayout(new QVBoxLayout); QWidget* pContainerA(new QWidget); QWidget* pContainerB(new QWidget); mpsaA = new QScrollArea; mpsaA->setWidget(pContainerA); mpsaA->setFixedHeight(intFixedHeight); mpsaA->setWidgetResizable(true); pvbxLayout->addWidget(mpsaA); mpFormLayoutA = new QFormLayout; mpFormLayoutA->setContentsMargins(0,0,0,0); mpFormLayoutA->setSpacing(0); mpFormLayoutA->setHorizontalSpacing(10); pContainerA->setLayout(mpFormLayoutA); mpButtonGroupA = new QButtonGroup(pContainerA); mpButtonGroupA->setObjectName("Button Group A"); mpsaB = new QScrollArea; mpsaB->setWidget(pContainerB); mpsaB->setFixedHeight(intFixedHeight); mpsaB->setWidgetResizable(true); pvbxLayout->addWidget(mpsaB); mpFormLayoutB = new QFormLayout; mpFormLayoutB->setContentsMargins(0,0,0,0); mpFormLayoutB->setSpacing(0); mpFormLayoutB->setHorizontalSpacing(10); pContainerB->setLayout(mpFormLayoutB); mpButtonGroupB = new QButtonGroup(pContainerB); mpButtonGroupB->setObjectName("Button Group B"); for( int i=1; i<=10; i++ ) { QRadioButton* pRadioButton(new QRadioButton(QString("Radio %1").arg(i))); if ( i < 6 ) { mpButtonGroupA->addButton(pRadioButton); mpFormLayoutA->addRow(QString::number(i), pRadioButton); } else { mpButtonGroupB->addButton(pRadioButton); mpFormLayoutB->addRow(QString::number(i), pRadioButton); } QObject::connect(pRadioButton, &QRadioButton::clicked, [pRadioButton](bool blnChecked) { qDebug() << pRadioButton->group() << ":" << pRadioButton->text() << " Checked: " << blnChecked; } ); } pvbxLayout->addWidget(new QPushButton("HELLO")); ui->centralwidget->setLayout(pvbxLayout); } MainWindow::~MainWindow() { delete ui; }
This works, now based not the above I want to implement in my main application, my layout class:
class clsQtLayout { friend class clsXMLnode; private: clsXMLnode* mpobjNode; QScrollArea* mpobjScroller; public: static const char mscszFormLayout[]; static const char mscszGridLayout[]; static const char mscszHBoxLayout[]; static const char mscszVBoxLayout[]; explicit clsQtLayout(clsXMLnode* pobjNode, const QSize& crszFixed , QWidget* pobjParent); void addWidget(QWidget* pobjWidget); QLayout* pobjLayout(); QScrollArea* pobjScroller() { return mpobjScroller; } };
The implementation:
/** * File: clsQtLayout.cpp * Notes: Contains implementation of the class clsQtLayout * History: 2021/10/23 Created by Simon Platten */ #include <clsQtLayout.h> //Static initialisation const char clsQtLayout::mscszFormLayout[] = "QFormLayout"; const char clsQtLayout::mscszGridLayout[] = "QGridLayout"; const char clsQtLayout::mscszHBoxLayout[] = "QHBoxLayout"; const char clsQtLayout::mscszVBoxLayout[] = "QVBoxLayout"; /** * @brief clsQtLayout::clsQtLayout * @param pobjNode : Pointer to XML node * @param crszFixed : Constant reference to fixed size * @param pobjParent : Pointer to parent widget */ clsQtLayout::clsQtLayout(clsXMLnode* pobjNode, const QSize& crszFixed, QWidget* pobjParent) : mpobjNode(pobjNode) , mpobjScroller(nullptr) { static const char scszConstructor[] = "clsQtLayout::clsQtLayout"; Q_ASSERT_X(pobjNode!=nullptr, scszConstructor, "No node supplied!"); Q_ASSERT_X(pobjParent!=nullptr, scszConstructor, "No parent widget supplied!"); QString strType(pobjNode->strGetAttribute(clsXMLnode::mscszAttrType)), strName; int intFixedHeight, intFixedWidth; intFixedHeight = intFixedWidth = 0; //Create widget for the layout mpobjNode->setWidget(new QWidget); //What type of layout? if ( strType.compare(clsXMLnode::mscszLayoutForm) == 0 ) { mpobjNode->setLayout(new QFormLayout); strName = clsQtLayout::mscszFormLayout; } else if ( strType.compare(clsXMLnode::mscszLayoutGrid) == 0 ) { mpobjNode->setLayout(new QGridLayout); strName = clsQtLayout::mscszGridLayout; } else if ( strType.compare(clsXMLnode::mscszLayoutHorizontal) == 0 ) { mpobjNode->setLayout(new QHBoxLayout); intFixedWidth = crszFixed.width(); strName = clsQtLayout::mscszHBoxLayout; } else if ( strType.compare(clsXMLnode::mscszLayoutVertical) == 0 ) { mpobjNode->setLayout(new QVBoxLayout); intFixedHeight = crszFixed.height(); strName = clsQtLayout::mscszVBoxLayout; } QLayout* pobjLayout(mpobjNode->pobjGetLayout()); Q_ASSERT_X(pobjLayout!=nullptr, scszConstructor, "Layout has not been created!"); QString strParentName(pobjParent->objectName()); if ( strParentName.isEmpty() != true ) { strName += ", " + pobjParent->objectName(); } pobjLayout->setObjectName(strName); if ( intFixedHeight > 0 || intFixedWidth > 0 ) { mpobjScroller = new QScrollArea; mpobjScroller->setWidget(mpobjNode->pobjGetWidget()); if ( intFixedHeight > 0 ) { mpobjScroller->setFixedHeight(intFixedHeight); } if ( intFixedWidth > 0 ) { mpobjScroller->setFixedWidth(intFixedWidth); } mpobjScroller->setWidgetResizable(true); pobjLayout->addWidget(mpobjScroller); } } /** * @brief clsQtLayout::addWidget * @param pobjWidget Pointer to widget to add */ void clsQtLayout::addWidget(QWidget *pobjWidget) { if ( pobjWidget != nullptr && mpobjNode != nullptr ) { QLayout* pobjLayout(mpobjNode->pobjGetLayout()); if ( pobjLayout != nullptr ) { pobjLayout->addWidget(pobjWidget); } } }
Using the debugger I've single stepped to the line:
pobjLayout->addWidget(mpobjScroller);
In the clsQtLayout constructor, this doesn't return and hangs the application, no error message is displayed execution just hangs.
I've looked at the various pointers and everything looks ok, can anyone suggest what I may have done wrong as I've compare the source with the original prototype and cannot see whats wrong.
[Edit] I've modified the source passing pobjParent to the layouts on creation, no difference, same result, locks up on addWidget.
-
I have written a simple test application:
#include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , mpButtonGroupA(nullptr) , mpButtonGroupB(nullptr) , mpFormLayoutA(nullptr) , mpFormLayoutB(nullptr) , mpsaA(nullptr) , mpsaB(nullptr) , ui(new Ui::MainWindow) { ui->setupUi(this); int intFixedHeight(fontMetrics().height() * 3); QVBoxLayout* pvbxLayout(new QVBoxLayout); QWidget* pContainerA(new QWidget); QWidget* pContainerB(new QWidget); mpsaA = new QScrollArea; mpsaA->setWidget(pContainerA); mpsaA->setFixedHeight(intFixedHeight); mpsaA->setWidgetResizable(true); pvbxLayout->addWidget(mpsaA); mpFormLayoutA = new QFormLayout; mpFormLayoutA->setContentsMargins(0,0,0,0); mpFormLayoutA->setSpacing(0); mpFormLayoutA->setHorizontalSpacing(10); pContainerA->setLayout(mpFormLayoutA); mpButtonGroupA = new QButtonGroup(pContainerA); mpButtonGroupA->setObjectName("Button Group A"); mpsaB = new QScrollArea; mpsaB->setWidget(pContainerB); mpsaB->setFixedHeight(intFixedHeight); mpsaB->setWidgetResizable(true); pvbxLayout->addWidget(mpsaB); mpFormLayoutB = new QFormLayout; mpFormLayoutB->setContentsMargins(0,0,0,0); mpFormLayoutB->setSpacing(0); mpFormLayoutB->setHorizontalSpacing(10); pContainerB->setLayout(mpFormLayoutB); mpButtonGroupB = new QButtonGroup(pContainerB); mpButtonGroupB->setObjectName("Button Group B"); for( int i=1; i<=10; i++ ) { QRadioButton* pRadioButton(new QRadioButton(QString("Radio %1").arg(i))); if ( i < 6 ) { mpButtonGroupA->addButton(pRadioButton); mpFormLayoutA->addRow(QString::number(i), pRadioButton); } else { mpButtonGroupB->addButton(pRadioButton); mpFormLayoutB->addRow(QString::number(i), pRadioButton); } QObject::connect(pRadioButton, &QRadioButton::clicked, [pRadioButton](bool blnChecked) { qDebug() << pRadioButton->group() << ":" << pRadioButton->text() << " Checked: " << blnChecked; } ); } pvbxLayout->addWidget(new QPushButton("HELLO")); ui->centralwidget->setLayout(pvbxLayout); } MainWindow::~MainWindow() { delete ui; }
This works, now based not the above I want to implement in my main application, my layout class:
class clsQtLayout { friend class clsXMLnode; private: clsXMLnode* mpobjNode; QScrollArea* mpobjScroller; public: static const char mscszFormLayout[]; static const char mscszGridLayout[]; static const char mscszHBoxLayout[]; static const char mscszVBoxLayout[]; explicit clsQtLayout(clsXMLnode* pobjNode, const QSize& crszFixed , QWidget* pobjParent); void addWidget(QWidget* pobjWidget); QLayout* pobjLayout(); QScrollArea* pobjScroller() { return mpobjScroller; } };
The implementation:
/** * File: clsQtLayout.cpp * Notes: Contains implementation of the class clsQtLayout * History: 2021/10/23 Created by Simon Platten */ #include <clsQtLayout.h> //Static initialisation const char clsQtLayout::mscszFormLayout[] = "QFormLayout"; const char clsQtLayout::mscszGridLayout[] = "QGridLayout"; const char clsQtLayout::mscszHBoxLayout[] = "QHBoxLayout"; const char clsQtLayout::mscszVBoxLayout[] = "QVBoxLayout"; /** * @brief clsQtLayout::clsQtLayout * @param pobjNode : Pointer to XML node * @param crszFixed : Constant reference to fixed size * @param pobjParent : Pointer to parent widget */ clsQtLayout::clsQtLayout(clsXMLnode* pobjNode, const QSize& crszFixed, QWidget* pobjParent) : mpobjNode(pobjNode) , mpobjScroller(nullptr) { static const char scszConstructor[] = "clsQtLayout::clsQtLayout"; Q_ASSERT_X(pobjNode!=nullptr, scszConstructor, "No node supplied!"); Q_ASSERT_X(pobjParent!=nullptr, scszConstructor, "No parent widget supplied!"); QString strType(pobjNode->strGetAttribute(clsXMLnode::mscszAttrType)), strName; int intFixedHeight, intFixedWidth; intFixedHeight = intFixedWidth = 0; //Create widget for the layout mpobjNode->setWidget(new QWidget); //What type of layout? if ( strType.compare(clsXMLnode::mscszLayoutForm) == 0 ) { mpobjNode->setLayout(new QFormLayout); strName = clsQtLayout::mscszFormLayout; } else if ( strType.compare(clsXMLnode::mscszLayoutGrid) == 0 ) { mpobjNode->setLayout(new QGridLayout); strName = clsQtLayout::mscszGridLayout; } else if ( strType.compare(clsXMLnode::mscszLayoutHorizontal) == 0 ) { mpobjNode->setLayout(new QHBoxLayout); intFixedWidth = crszFixed.width(); strName = clsQtLayout::mscszHBoxLayout; } else if ( strType.compare(clsXMLnode::mscszLayoutVertical) == 0 ) { mpobjNode->setLayout(new QVBoxLayout); intFixedHeight = crszFixed.height(); strName = clsQtLayout::mscszVBoxLayout; } QLayout* pobjLayout(mpobjNode->pobjGetLayout()); Q_ASSERT_X(pobjLayout!=nullptr, scszConstructor, "Layout has not been created!"); QString strParentName(pobjParent->objectName()); if ( strParentName.isEmpty() != true ) { strName += ", " + pobjParent->objectName(); } pobjLayout->setObjectName(strName); if ( intFixedHeight > 0 || intFixedWidth > 0 ) { mpobjScroller = new QScrollArea; mpobjScroller->setWidget(mpobjNode->pobjGetWidget()); if ( intFixedHeight > 0 ) { mpobjScroller->setFixedHeight(intFixedHeight); } if ( intFixedWidth > 0 ) { mpobjScroller->setFixedWidth(intFixedWidth); } mpobjScroller->setWidgetResizable(true); pobjLayout->addWidget(mpobjScroller); } } /** * @brief clsQtLayout::addWidget * @param pobjWidget Pointer to widget to add */ void clsQtLayout::addWidget(QWidget *pobjWidget) { if ( pobjWidget != nullptr && mpobjNode != nullptr ) { QLayout* pobjLayout(mpobjNode->pobjGetLayout()); if ( pobjLayout != nullptr ) { pobjLayout->addWidget(pobjWidget); } } }
Using the debugger I've single stepped to the line:
pobjLayout->addWidget(mpobjScroller);
In the clsQtLayout constructor, this doesn't return and hangs the application, no error message is displayed execution just hangs.
I've looked at the various pointers and everything looks ok, can anyone suggest what I may have done wrong as I've compare the source with the original prototype and cannot see whats wrong.
[Edit] I've modified the source passing pobjParent to the layouts on creation, no difference, same result, locks up on addWidget.
@SPlatten , I think I found the issue, at least it doesn't lock up now, still not the results I wanted in that the content I'm adding to the layout isn't inside the layout:
/** * File: clsQtLayout.cpp * Notes: Contains implementation of the class clsQtLayout * History: 2021/10/23 Created by Simon Platten */ #include <clsQtLayout.h> //Static initialisation const char clsQtLayout::mscszFormLayout[] = "QFormLayout"; const char clsQtLayout::mscszGridLayout[] = "QGridLayout"; const char clsQtLayout::mscszHBoxLayout[] = "QHBoxLayout"; const char clsQtLayout::mscszVBoxLayout[] = "QVBoxLayout"; /** * @brief clsQtLayout::clsQtLayout * @param pobjNode : Pointer to XML node * @param crszFixed : Constant reference to fixed size * @param pobjParent : Pointer to parent widget */ clsQtLayout::clsQtLayout(clsXMLnode* pobjNode, const QSize& crszFixed, QWidget* pobjParent) : mpobjNode(pobjNode) , mpobjScroller(nullptr) { static const char scszConstructor[] = "clsQtLayout::clsQtLayout"; Q_ASSERT_X(pobjNode!=nullptr, scszConstructor, "No node supplied!"); Q_ASSERT_X(pobjParent!=nullptr, scszConstructor, "No parent widget supplied!"); QString strType(pobjNode->strGetAttribute(clsXMLnode::mscszAttrType)); int intFixedHeight, intFixedWidth; intFixedHeight = crszFixed.height(); intFixedWidth = crszFixed.width(); //Create widget for the layout mpobjNode->setWidget(new QWidget); //What type of layout? if ( strType.compare(clsXMLnode::mscszLayoutForm) == 0 ) { mpobjNode->setLayout(new QFormLayout(pobjParent)); } else if ( strType.compare(clsXMLnode::mscszLayoutGrid) == 0 ) { mpobjNode->setLayout(new QGridLayout(pobjParent)); } else if ( strType.compare(clsXMLnode::mscszLayoutHorizontal) == 0 ) { mpobjNode->setLayout(new QHBoxLayout(pobjParent)); } else if ( strType.compare(clsXMLnode::mscszLayoutVertical) == 0 ) { mpobjNode->setLayout(new QVBoxLayout(pobjParent)); } else { //No valid layout supplied Q_ASSERT_X(nullptr, scszConstructor, "Layout has not been created!"); return; } //Get the parent layout clsXMLnode* pobjParentNode(mpobjNode->pobjGetParent()); QLayout* pobjLayout(pobjParentNode->pobjGetLayout()); if ( intFixedHeight > 0 || intFixedWidth > 0 ) { mpobjScroller = new QScrollArea; mpobjScroller->setWidget(mpobjNode->pobjGetWidget()); if ( intFixedHeight > 0 ) { mpobjScroller->setFixedHeight(intFixedHeight); } if ( intFixedWidth > 0 ) { mpobjScroller->setFixedWidth(intFixedWidth); } mpobjScroller->setWidgetResizable(true); pobjLayout->addWidget(mpobjScroller); } } /** * @brief clsQtLayout::addWidget * @param pobjWidget Pointer to widget to add */ void clsQtLayout::addWidget(QWidget *pobjWidget) { if ( pobjWidget != nullptr && mpobjNode != nullptr ) { QLayout* pobjLayout(mpobjNode->pobjGetLayout()); if ( pobjLayout != nullptr ) { pobjLayout->addWidget(pobjWidget); } } }