【问题标题】:QScrollArea with dynamically added widget带有动态添加小部件的 QScrollArea
【发布时间】:2018-03-14 19:09:22
【问题描述】:

我在 QScrollArea 中放置自定义小部件时遇到了一些问题。我的自定义小部件在 QGridLayout 中包含 4 个标签来填充它。现在我想将此小部件保留在 QScrollArea 中并能够向其添加更多标签,但我希望其中只有 4 个显示在视口中。

这就是带有 4 个标签的小部件在 QScrollArea 中的样子:

这是添加两个标签后 QScrollArea 中的小部件,其中红色矩形是视口。

我怎样才能达到这样的效果?

====================================

更新

我最终用以下代码解决了我的问题。它可能需要一些小的间距修复。

#include "QtGuiApplication2.h"
#include "qscrollarea.h"
#include "CustomWidget.h"

QtGuiApplication2::QtGuiApplication2(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);

QScrollArea * qScrollArea = new QScrollArea();

CustomWidget * customWidget = new CustomWidget(this);
qScrollArea->setWidget(customWidget);
qScrollArea->setWidgetResizable(true);
qScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);

ui.mainLayout->addWidget(qScrollArea, 1, 1, 1, 1);
}

CustomWidget 类:

#include "CustomWidget.h"

#include "qlabel.h"

CustomWidget::CustomWidget(QWidget *parent) : QWidget(parent)
{
labelsNum = 4;
rows = 2;
layout = new QGridLayout();
this->setLayout(layout);
QMargins * margin = new QMargins(10, 10, 10, 10);
layout->setContentsMargins(*margin);
layout->setHorizontalSpacing(5);
layout->setVerticalSpacing(5);
initLabels();
addLabels();
}

CustomWidget::~CustomWidget()
{
}

void CustomWidget::initLabels()
{
int cols = labelsNum / rows;

for (int i = 0; i < labelsNum; i++)
{
    CustomLabel * label = new CustomLabel(this);
    label->setText(QString::number(i));
    label->setFrameShape(QFrame::Box);

    labels.append(label);
}

for (int i = 0; i < rows; i++)
{
    for (int j = 0; j < cols; j++)
    {
        layout->addWidget(labels.at(i * cols + j), i + 1, j + 1, 1, 1);
    }
}
}

void CustomWidget::addLabels()
{

int numLabels = labels.size();

for (int i = 0; i < 2; i++)
{
    CustomLabel * label = new CustomLabel(this);
    label->setText(QString::number(numLabels + i));
    label->setFrameShape(QFrame::Box);

    labels.append(label);
}

labelsNum += rows;
int cols = labelsNum / rows;

for (int i = 0; i < rows; i++)
{
    for (int j = 0; j < cols; j++)
    {
        layout->addWidget(labels.at(i * cols + j), i + 1, j + 1, 1, 1);
    }
}
}

void CustomWidget::resizeEvent(QResizeEvent * e)
{
QWidget::resizeEvent(e);
QSize size = viewportSize;

//Substract all the spacing from view size
int horizontalSpacing = ((4 / rows) - 1) * layout->horizontalSpacing();
int verticalSpacing = (rows - 1) * layout->verticalSpacing();
size -= QSize(layout->margin() * 2 + horizontalSpacing, layout->margin()      * 2 + verticalSpacing);

size *= 0.5;
for (int i = 0; i < labels.size(); i++)
{
    labels.at(i)->resizeEvent(e, size);
}
} 

以及自定义标签:

#include "CustomLabel.h"

CustomLabel::CustomLabel(QWidget *parent): QLabel(parent)
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
setMinimumSize(QSize(50, 50));
}

CustomLabel::~CustomLabel()
{
}

void CustomLabel::resizeEvent(QResizeEvent * e, QSize size)
{
this->setFixedSize(size);
}

【问题讨论】:

  • 请出示您的代码
  • 据我所知,您应该将标签放在布局中,然后放在小部件中,然后滚动区域设置小部件。
  • @Marco 是的,我就是这么做的。问题是当我放置超过 4 个时,当布局调整它们的大小时,它会在视口中显示所有这些。我希望它们都占用 1/4 的视口空间。

标签: c++ qt qt5 qscrollarea qlayout


【解决方案1】:

要获得您想要的行为,您必须设置大小,为此我创建了以下类,它继承自 QScrollArea,内部有一个 QGridLayout。对于此类,您必须确定可见行和列的数量以及小部件的固定大小,在您的情况下为QLabel。

#ifndef HORIZONTALSCROLLAREA_H
#define HORIZONTALSCROLLAREA_H

#include <QGridLayout>
#include <QResizeEvent>
#include <QScrollArea>
#include <QScrollBar>

class HorizontalScrollArea : public QScrollArea
{
    QWidget *contentWidget;
    QGridLayout *grid;
    int nRows;
    int nColumns;
public:
    HorizontalScrollArea(int rows, int cols, QWidget *parent = Q_NULLPTR)
        :QScrollArea(parent), nRows(rows), nColumns(cols)
    {
        setWidgetResizable(true);
        contentWidget = new QWidget(this);
        setWidget(contentWidget);
        grid = new QGridLayout(contentWidget);
        setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    }

    void addWidget(QWidget *w, int row, int col){
        grid->addWidget(w, row, col);
        adaptSize();
    }

    int columnCount() const{
        if(grid->count() == 0){
            return 0;
        }
        return grid->columnCount();
    }

private:
    void adaptSize(){
        if(columnCount() >= nColumns ){
            int w = 1.0*(width() - grid->horizontalSpacing()*(nColumns+1.6))/nColumns;
            int wCorrected = w*columnCount() + grid->horizontalSpacing()*(columnCount()+2);
            contentWidget->setFixedWidth(wCorrected);
        }
        contentWidget->setFixedHeight(viewport()->height());
    }
protected:
    void resizeEvent(QResizeEvent *event){
        QScrollArea::resizeEvent(event);
        adaptSize();
    }
};

#endif // HORIZONTALSCROLLAREA_H

以下部分为示例:

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QWidget w;

    w.setLayout(new QVBoxLayout);

    QPushButton btn("Add", &w);

    int nrows = 2;
    int ncols = 2;

    HorizontalScrollArea scroll(nrows, ncols);

    w.layout()->addWidget(&btn);
    w.layout()->addWidget(&scroll);

    QObject::connect(&btn, &QPushButton::clicked, [&scroll, &nrows](){
        int column = scroll.columnCount();
        for(int row=0; row < nrows; row++){
            QLabel *label = new QLabel(QString("label: %1 %2")
                                       .arg(row)
                                       .arg(column));
            label->setFrameShape(QFrame::Box);
            label->setAlignment(Qt::AlignCenter);
            QColor color(qrand() % 256, qrand() % 256, qrand() % 256);
            label->setStyleSheet(QString("QLabel { background-color : %1;}")
                                 .arg(color.name()));
            scroll.addWidget(label, row, column);
        }
    });
    w.show();
    return a.exec();
}

下面link是完整的例子。

输出:

【讨论】:

  • 嗨,非常感谢。这几乎就是我所需要的。您的示例中唯一的问题是标签和滚动区域的大小不可调整。如何纠正?
  • 抱歉不够精确。我希望所有标签都占据视口空间的 1/4(或通常是 1/n 的空间)。我提供了一些代码,所以你可以看看我现在有什么。
  • 我以不同的方式解决了我的问题,但您的解决方案也非常好。感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 2012-05-17
  • 1970-01-01
  • 2012-04-14
  • 1970-01-01
  • 2018-11-27
  • 1970-01-01
  • 1970-01-01
  • 2010-12-30
相关资源
最近更新 更多