c++qtqt-designerqt5.3qgroupbox

qt how to add a groupbox that contains some widgets dynamically with a pushbutton?


I have a groupbox that contains some pushbuttons and sliders. I want that when I click on a button, a new groupbox that is the same with the former one should appear under the first one. Whenever I click on the button, same situation should happen dynamically. Since I need up to 32 groupbox like that, I don't want to put all groupboxes manually. So, how can I do this?


Solution

  • First off, a layout is highly recommended.

    Here is an example (I have done this before). You can derive a class from QScrollArea, then set in the constructor the layouts you want to have.

    In here a simple button called Add is in the window. If you press it, a row gets added and initialized with default values (0, 0, 0) <- integers. In the live program, I load the values from a file/database and initialize it then.

    You may want to use different layout(s) and a different setup, but this should give you the idea. I'm sure you get where you want with a little more experimenting.

    //Structure to keep track of the added widgets easier
    struct ItemRow
    {
        ItemRow(QLineEdit *entry, QLineEdit *amount, QComboBox *box)
            : m_Entry(entry)
            , m_Amount(amount)
            , m_Box(box)
        { }
    
        ItemRow(void)
            : m_Entry(nullptr)
            , m_Amount(nullptr)
            , m_Box(nullptr)
        { }
    
        QLineEdit *m_Entry;
        QLineEdit *m_Amount;
        QComboBox *m_Box;
    };
    

    The class declaration.

    class MyScrollArea : public QScrollArea
    {
        Q_OBJECT
    
    public:
        explicit MyScrollArea(QWidget *parent = 0);
        ~MyScrollArea();
        //...
        void OnAddButtonPressed(void);
        void DrawButtonLayout(void);
        void AddRow(int val1, int val2, int val3); //Use own parameters
    
    private:
        QVBoxLayout *m_LayoutFirstRow;
        QVBoxLayout *m_LayoutSecondRow;
        QVBoxLayout *m_LayoutThirdRow;
        //...
        QVBoxLayout *m_LayoutButton;
        //...
        QList<QPushButton*> m_Buttons;
        QVector<ItemRow> m_ItemRows;
    }
    

    The implementation.

    MyScrollArea::MyScrollArea(QWidget *parent) :
        QScrollArea(parent),
        ui(new Ui::MyScrollArea)
    {
        ui->setupUi(this);
        setWidget(new QWidget);
        setWidgetResizable(true);
        setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
    
        QHBoxLayout *mainLayout = new QHBoxLayout(this);
    
        m_LayoutFirstRow    = new QVBoxLayout();
        m_LayoutSecondRow   = new QVBoxLayout();
        m_LayoutThirdRow    = new QVBoxLayout();
        m_LayoutButton      = new QVBoxLayout();
    
        widget()->setLayout(mainLayout);
    
        mainLayout->addLayout(m_LayoutFirstRow);
        mainLayout->addLayout(m_LayoutSecondRow);
        mainLayout->addLayout(m_LayoutThirdRow);
        mainLayout->addLayout(m_LayoutButton);
    
        DrawButtonLayout();
    }
    
    RewardDialog::~RewardDialog()
    {
        delete ui;
    }
    
    void MyScrollArea::OnAddButtonPressed(void)
    {
        AddRow(0, 0, 0);
    }
    
    void MyScrollArea::DrawButtonLayout(void)
    {
        QPushButton *addBtn = new QPushButton("Add");
        connect(addBtn, SIGNAL(clicked()), this, SLOT(OnAddButtonPressed()));
        m_LayoutButton->addWidget(addBtn);
        m_Buttons.push_back(addBtn); //Keep somewhere track of the button(s) if needed - example: put in QList (not the best approach though)
    }
    
    void MyScrollArea::AddRow(int val1, int val2, int val3)
    {
        QLineEdit *pEntry = new QLineEdit(QString::number(val1));
        pEntry->setValidator(new QIntValidator());
        QLineEdit *pAmount = new QLineEdit(QString::number(val2));
        pAmount->setValidator(new QIntValidator());
        QComboBox *pBox = new QComboBox();
        InitComboBox(pBox, val3); //Initialize the combo-box (use connect if you wish) - code not included
    
        m_LayoutFirstRow->addWidget(pEntry);
        m_LayoutSecondRow->addWidget(pAmount);
        m_LayoutThirdRow->addWidget(pBox);
    
        ItemRow row;
        row.m_Entry = pEntry;
        row.m_Amount = pAmount;
        row.m_Box = pBox;
        m_ItemRows.push_back(row);
    }
    

    Leave a comment if something seems wrong, I put this together in Notepad++.

    Note: The documentation-link is for QT4.8, as 5.3 is not available anymore, but my code is from version 5.3 too.