How to extend the length of Widgets within a Qscrollarea?

Asked

Viewed 168 times

4

I’m looking to build a question form in Qt. As there are several questions to be answered, it is necessary to allow the scrolling of the form, and so I used a QScrollArea. Questions are all answered on a scale Likert, then I adjusted the alignment of the layout that contains them to the left and spaced the options manually. That is, everything is aligned to the left. I also implemented an alternate color style, just to make it more enjoyable for the user to differentiate the questions when scrolling the form.

Here is an image of the MCVE that I prepared (and is below). The main problem is that I can’t get this "zebrado" to extend to the end of the form (on the right, indicated in the blue box in the image). There is also the space that looks like a margin on the left (indicated in the red box).

inserir a descrição da imagem aqui

To solve the main problem, I have already tried to change the size restrictions of the kids layouts (using setSizeConstraint) and even add a reamer (stretch) after the last option (as can be seen in the code line marked with comment), but none of these options works. And for the secondary problem, well, I’ve tried changing the margins via stylesheet (as in code) and even using the method setMargin of one’s own class QWidget, but nothing works.

What works for the main problem is to set a minimum or fixed size for the options container (the object in pRow), but I cannot use this option because the window can have the size adjusted by the user (or depending on the screen dimensions available to it). Also because it doesn’t solve the secondary problem, and I wouldn’t want to capture window resize event to adjust the size manually - since then I lose the advantage of using layouts.

Any suggestions?

MCVE code

#include <QApplication>
#include <QWidget>
#include <QRadioButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QFrame>
#include <QLabel>
#include <QRadioButton>
#include <QScrollArea>

#define STYLE_SHEET "                               \
                    QWidget#plainArea               \
                    {                               \
                        background-color: #ffffff;  \
                        padding: 0px 0px 0px 0px;   \
                        margin: 0px 0px 0px 0px;    \
                        border-width: 0px;          \
                    }                               \
                                                    \
                    QLabel#headerTitle              \
                    {                               \
                        font-size: 25px; }          \
                    }                               \
                                                    \
                    QLabel#questionTitle            \
                    {                               \
                        font-size: 20px;            \
                    }                               \
                                                    \
                    QRadioButton#optionTitle        \
                    {                               \
                        font-size: 16px;            \
                    }                               \
                                                    \
                    QWidget#highlightedrow          \
                    {                               \
                        background-color: #efd3d2;  \
                    }                               \
                    "

QWidget* createQuestionnaire(QWidget *pParent)
{
    QWidget *pQuestionnaire = new QWidget(pParent);
    pQuestionnaire->setObjectName("plainArea");
    pQuestionnaire->setLayout(new QVBoxLayout());
    pQuestionnaire->layout()->setAlignment(Qt::AlignTop);

    // Cabeçalho
    QLabel *pTitle = new QLabel("Por favor, responda às perguntas a seguir.", pQuestionnaire);
    pTitle->setObjectName("headerTitle");
    pQuestionnaire->layout()->addWidget(pTitle);

    QFrame *pLine = new QFrame(pQuestionnaire);
    pLine->setFrameStyle(QFrame::HLine);
    pLine->setLineWidth(4);
    pQuestionnaire->layout()->addWidget(pLine);
    static_cast<QBoxLayout*>(pQuestionnaire->layout())->addSpacing(10);

    // Scroll Area
    QScrollArea *pScroll = new QScrollArea(pQuestionnaire);
    pScroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    pScroll->setObjectName("plainArea");
    pScroll->setLayout(new QVBoxLayout());
    pQuestionnaire->layout()->addWidget(pScroll);

    QWidget *pArea = new QWidget(pQuestionnaire);
    pArea->setObjectName("plainArea");
    pArea->setLayout(new QVBoxLayout());
    pArea->layout()->setSizeConstraint(QLayout::SetMinAndMaxSize);

    pScroll->setWidget(pArea);

    // Questões
    QStringList lFruits = {
        "Abacate", "Amora", "Ameixa", "Acerola", "Abacaxi", "Açaí",
        "Banana", "Bacuri", "Buriti", "Butiá", "Bacaba", "Carambola",
        "Cajá", "Caju", "Cereja", "Cacau", "Caqui", "Cupuaçu", "Damasco",
        "Figo", "Framboesa", "Fruta Pão", "Graviola", "Goiaba", "Goiaba Branca",
        "Groselha", "Guaraná", "Grumixama", "Guariroba", "Ingá", "Ibapó",
        "Itu", "Ingá Dedo", "Ingá Branco", "Jaca", "Jabuticaba", "Jambo",
        "Jenipapo", "Jatobá", "Kiwi", "Laranja", "Limão", "Lima Doce",
        "Lixia", "Melancia", "Mamão", "Melão", "Maracujá", "Manga",
        "Macadâmia", "Maçã", "Mangaba", "Mexerica", "Nectarina", "Noz",
        "Nêspera", "Olho-De-Boi", "Pera", "Pêssego", "Pitaya", "Pitanga",
        "Pinha", "Pinhão", "Pitomba", "Pocã", "Quina", "Rabutan", "Romã",
        "Sapoti", "Sapucaia", "Salok", "Saputá", "Tangerina", "Tomate",
        "Tamarindo", "Toranja", "Taiúva", "Uva", "Uxi", "Uvaia", "Umbu",
        "Veludo", "Wampi", "Xixá"
    };

    QStringList lOptions = { "detesto", "gosto pouco", "gosto", "gosto muito", "adoro" };

    for(int i = 0; i < lFruits.size(); i++)
    {
        QWidget *pRow = new QWidget(pQuestionnaire);
        pArea->layout()->addWidget(pRow);

        if(i % 2)
            pRow->setObjectName("highlightedrow");

        pRow->setLayout(new QVBoxLayout());
        QLabel *pQuestion = new QLabel(QString("%1 - Você gosta de %2?").arg(i+1).arg(lFruits.at(i)), pRow);
        pQuestion->setObjectName("questionTitle");
        pRow->layout()->addWidget(pQuestion);

        QWidget *pOptions = new QWidget(pRow);
        pRow->layout()->addWidget(pOptions);
        pOptions->setLayout(new QHBoxLayout());
        pOptions->layout()->setAlignment(Qt::AlignLeft);

        static_cast<QBoxLayout*>(pOptions->layout())->addSpacing(60);
        foreach(QString sOption, lOptions)
        {
            QRadioButton *pButton = new QRadioButton(sOption, pOptions);
            pButton->setCursor(Qt::PointingHandCursor);
            pButton->setObjectName("optionTitle");
            pOptions->layout()->addWidget(pButton);
            static_cast<QBoxLayout*>(pOptions->layout())->addSpacing(20);
        }
        static_cast<QBoxLayout*>(pOptions->layout())->addStretch(); // <--- Stretch não funciona!
    }

    return pQuestionnaire;
}

int main(int argc, char** argv)
{
    QApplication oApp(argc, argv);

    QWidget *pWindow = new QWidget();
    pWindow->setObjectName("plainArea");
    pWindow->setStyleSheet(STYLE_SHEET);
    pWindow->setWindowTitle("MCVE para o SOPT");

    pWindow->setLayout(new QVBoxLayout());
    pWindow->layout()->addWidget(createQuestionnaire(pWindow));

    pWindow->show();
    pWindow->resize(800, 600);
    return oApp.exec();
}

P.S.: Oh, how I hate the QScrollArea of Qt, you see. rs

  • 1

    I’ll have them frame it, take a picture and ask all the questions that don’t go forward :)

  • Let go of the exaggerating hand, go. :)

  • 1

    All right, I don’t give orders to frame :P

1 answer

5


I’ve figured out how to solve both problems.

The main problem is that the QScrollArea does not work well with an internal widget that contains daughter widgets arranged in layout if the scroll widget is not allowed to adjust its size automatically. For this, just define how true the value of the property widgetResizable.

The cool thing is that it’s not at all clear main description of the documentation. Only the following is included in the documentation:

The view can be made to be resizable with the setWidgetResizable() Function.

Upon reading this I imagined that a resizable widget would be... resizable and therefore not need Scroll! (after all, as the example of documentation is images, I imagined that they would be scaled to the size of the view port instead to display the scrollbars). But no, this property is what allows the widget to increase and decrease in size as it decides. Honestly, I don’t understand why anyone would need to use this property as a fake and use a scrolling area, but anyway...

For the secondary problem, it was simply easier to set the margins at 0 for all components via code with the method setMargin layout class, and did not see style sheet.

The final code, which results in the following screen, is presented below.

Canvas:

inserir a descrição da imagem aqui

Code:

#include <QApplication>
#include <QWidget>
#include <QRadioButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QFrame>
#include <QLabel>
#include <QRadioButton>
#include <QScrollArea>

#define STYLE_SHEET "                               \
                    QWidget#plainArea               \
                    {                               \
                        background-color: #ffffff;  \
                    }                               \
                                                    \
                    QLabel#headerTitle              \
                    {                               \
                        font-size: 25px; }          \
                    }                               \
                                                    \
                    QLabel#questionTitle            \
                    {                               \
                        font-size: 20px;            \
                    }                               \
                                                    \
                    QRadioButton#optionTitle        \
                    {                               \
                        font-size: 16px;            \
                    }                               \
                                                    \
                    QWidget#highlightedrow          \
                    {                               \
                        background-color: #efd3d2;  \
                    }                               \
                    "

QWidget* createQuestionnaire(QWidget *pParent)
{
    QWidget *pQuestionnaire = new QWidget(pParent);
    pQuestionnaire->setObjectName("plainArea");
    pQuestionnaire->setLayout(new QVBoxLayout());
    pQuestionnaire->layout()->setAlignment(Qt::AlignTop);
    pQuestionnaire->layout()->setMargin(0);

    // Cabeçalho
    QLabel *pTitle = new QLabel("Por favor, responda às perguntas a seguir.", pQuestionnaire);
    pTitle->setObjectName("headerTitle");
    pQuestionnaire->layout()->addWidget(pTitle);

    QFrame *pLine = new QFrame(pQuestionnaire);
    pLine->setFrameStyle(QFrame::HLine);
    pLine->setLineWidth(4);
    pQuestionnaire->layout()->addWidget(pLine);
    static_cast<QBoxLayout*>(pQuestionnaire->layout())->addSpacing(10);

    // Scroll Area
    QScrollArea *pScroll = new QScrollArea(pQuestionnaire);
    pScroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    pScroll->setObjectName("plainArea");
    pScroll->setLayout(new QVBoxLayout());
    pQuestionnaire->layout()->addWidget(pScroll);

    QWidget *pArea = new QWidget(pQuestionnaire);
    pArea->setObjectName("plainArea");
    pArea->setLayout(new QVBoxLayout());
    pArea->layout()->setSizeConstraint(QLayout::SetMinAndMaxSize);
    pArea->layout()->setMargin(0);

    pScroll->setWidget(pArea);
    pScroll->setWidgetResizable(true);

    // Questões
    QStringList lFruits = {
        "Abacate", "Amora", "Ameixa", "Acerola", "Abacaxi", "Açaí",
        "Banana", "Bacuri", "Buriti", "Butiá", "Bacaba", "Carambola",
        "Cajá", "Caju", "Cereja", "Cacau", "Caqui", "Cupuaçu", "Damasco",
        "Figo", "Framboesa", "Fruta Pão", "Graviola", "Goiaba", "Goiaba Branca",
        "Groselha", "Guaraná", "Grumixama", "Guariroba", "Ingá", "Ibapó",
        "Itu", "Ingá Dedo", "Ingá Branco", "Jaca", "Jabuticaba", "Jambo",
        "Jenipapo", "Jatobá", "Kiwi", "Laranja", "Limão", "Lima Doce",
        "Lixia", "Melancia", "Mamão", "Melão", "Maracujá", "Manga",
        "Macadâmia", "Maçã", "Mangaba", "Mexerica", "Nectarina", "Noz",
        "Nêspera", "Olho-De-Boi", "Pera", "Pêssego", "Pitaya", "Pitanga",
        "Pinha", "Pinhão", "Pitomba", "Pocã", "Quina", "Rabutan", "Romã",
        "Sapoti", "Sapucaia", "Salok", "Saputá", "Tangerina", "Tomate",
        "Tamarindo", "Toranja", "Taiúva", "Uva", "Uxi", "Uvaia", "Umbu",
        "Veludo", "Wampi", "Xixá"
    };

    QStringList lOptions = { "detesto", "gosto pouco", "gosto", "gosto muito", "adoro" };

    for(int i = 0; i < lFruits.size(); i++)
    {
        QWidget *pRow = new QWidget(pQuestionnaire);
        pArea->layout()->addWidget(pRow);

        if(i % 2)
            pRow->setObjectName("highlightedrow");

        pRow->setLayout(new QVBoxLayout());
        QLabel *pQuestion = new QLabel(QString("%1 - Você gosta de %2?").arg(i+1).arg(lFruits.at(i)), pRow);
        pQuestion->setObjectName("questionTitle");
        pRow->layout()->addWidget(pQuestion);

        QWidget *pOptions = new QWidget(pRow);
        pRow->layout()->addWidget(pOptions);
        pOptions->setLayout(new QHBoxLayout());
        pOptions->layout()->setAlignment(Qt::AlignLeft);

        static_cast<QBoxLayout*>(pOptions->layout())->addSpacing(60);
        foreach(QString sOption, lOptions)
        {
            QRadioButton *pButton = new QRadioButton(sOption, pOptions);
            pButton->setCursor(Qt::PointingHandCursor);
            pButton->setObjectName("optionTitle");
            pOptions->layout()->addWidget(pButton);
            static_cast<QBoxLayout*>(pOptions->layout())->addSpacing(20);
        }
    }

    return pQuestionnaire;
}

int main(int argc, char** argv)
{
    QApplication oApp(argc, argv);

    QWidget *pWindow = new QWidget();
    pWindow->setObjectName("plainArea");
    pWindow->setStyleSheet(STYLE_SHEET);
    pWindow->setWindowTitle("MCVE para o SOPT");

    pWindow->setLayout(new QVBoxLayout());
    pWindow->layout()->addWidget(createQuestionnaire(pWindow));
    pWindow->layout()->setMargin(0);

    pWindow->show();
    pWindow->resize(800, 600);
    return oApp.exec();
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.