如何创建可滚动的QVBoxLayout?

32
我正在尝试将一个 QVBoxLayout 放置在 QScrollArea 中,以使其在垂直方向上可以滚动。但是似乎无法添加项目。
我看到有人建议我创建一个内部小部件,让 ScrollArea 使用并将布局放置在其中,尽管它似乎没有起作用。我的结构应该是这样的:
+-------------------------------
| QScrollArea(realmScroll)
| +----------------------------
| | QWidget(realmScrollInner)
| | +-------------------------
| | | QVBoxLayout(realmLayout)

实现该功能的代码如下:

# Irrelevant, added for context (this works)
centralWidget = QWidget(self)
self.container = QVBoxLayout(centralWidget)
centralWidget.setLayout(self.container)
self.setCentralWidget(centralWidget)

# Where trouble starts
self.realmScroll = QScrollArea(self.container.widget())
self.realmScroll.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)

self.realmLayout = QVBoxLayout(self.container.widget())

self.realmScrollInner = QWidget(self.realmScroll)
self.realmScrollInner.setLayout(self.realmLayout)

self.realmScroll.setWidget(self.realmScrollInner)
self.container.addWidget(self.realmScroll)

# Doesn't add to realmLayout
self.realmLayout.addWidget(QLabel("test"))

我还在学习Qt(两天),所以深入解答我做错了什么会很有帮助。

更新:

似乎addWidget(QLabel())一直有效,直到将realmScrollInner设置为realmScroll的窗口部件。由于我想在UI显示后添加元素,因此必须这样做,但我不确定这是否正确:

self.realmLayout.addWidget(QLabel("test"))

# realmScrollInner bound to realmScroll
realmScroll.setWidget(realmScrollInner)
self.container.addWidget(realmScroll)

# Access realmScroll's widget and then layout to add
realmScroll.widget().layout().addWidget(QLabel("test"))

但如果在widget被绑定之前删除第一个对 addWidget 的调用(所以布局没有widgets),然后绑定到之后添加的ScrollArea widgets将不会显示。也许ScrollArea需要重绘(尽管我没有看到方法)?

更新2:在realmScroll或其包含的widget上调用repaint()无效,调用布局上的activate/update()也是如此。

3个回答

12

事实证明,我通过将布局设置为小部件的布局而被带入了错误的道路。实际上,做到这一点很简单:

scrollarea = QScrollArea(parent.widget())
layout = QVBoxLayout(scrollarea)
realmScroll.setWidget(layout.widget())

layout.addWidget(QLabel("Test"))

我相信最开始我尝试过这个方法,但是现在它可以工作了。

然而,这会导致布局项在垂直方向上被缩小,而不是使滚动区域添加滚动条。


1
我之前遇到过一个非常类似的问题,可以在这里看到解决方案:https://dev59.com/K2cs5IYBdhLWcg3wh0b7 - will

8

好的,我刚刚完成了对这个问题的解决。这是一个小部件,可以放置在滚动区域(scrollarea->setWidget)中,并且可以正确地工作。它包含一个QVBoxLayout和一组标签/列表部件对,每个部件对都在自己的小水平布局中,它基本上可以做到你想要的。

重要的是阅读QScrollArea文档部分关于大小提示和布局的内容,并找到需要在布局中设置sizeContraint QLayout::SetMinAndMaxSize的部分。

class MappingDisplayWidget : public QWidget
{
    Q_OBJECT
public:
    explicit MappingDisplayWidget(QWidget *parent = 0);
    void addFile(QString name);
private:
    QVBoxLayout *m_layout;
    QMap<QString, QListWidget *>  m_mappings;  
};


MappingDisplayWidget::MappingDisplayWidget(QWidget *parent) :
    QWidget(parent)
{
    m_layout = new QVBoxLayout;
    m_layout->setSizeConstraint(QLayout::SetMinAndMaxSize);
    setLayout(m_layout);
}


void MappingDisplayWidget::addFile(QString name) {
    if (m_mappings.find(name) == m_mappings.end()) {
        QWidget *widg = new QWidget;

        QHBoxLayout *lay = new QHBoxLayout;
        widg->setLayout(lay);

        QLabel *nlab = new QLabel(name);
        lay->addWidget(nlab);

        QListWidget *list = new QListWidget;
        lay->addWidget(list);

        m_layout->addWidget(widg);

        m_mappings[name] = list;
    }
}

我会在后面存储列表小部件的指针,以便稍后添加内容,这样做可以正常工作。


2

试着调用

self.realmScroll.setWidgetResizable(True)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接