添加小部件后,QScrollArea不会滚动到最大值

时间:2013-11-07 12:47:55

标签: layout qt4 qscrollarea

我的设置如下:

Main Window
  |- QHBoxLayout
       |- Some Widgets
       |- QScrollArea
       |    |- QHBoxLayout
       |         |- QGridLayout
       |              |- Widgets dynamically loaded in at runtime
       |         |- QVBoxLayout
       |- Some Widgets

在我添加小部件后,我希望滚动区域完全向下滚动。 我是这样做的:

this->ui->gridLayout_table->addWidget(/*Widget*/); // this works perfectly nice
this->ui->gridLayout_table->addWidget(/*Widget*/); // this also works perfectly nice
this->ui->scrollArea->verticalScrollBar()->setValue(this->ui->scrollArea->verticalScrollBar()->maximum());

在最后一个命令中,它滚动到最大值减去新添加的小部件的高度。在滚动之前有没有办法刷新更改?

提前致谢 卢卡斯

6 个答案:

答案 0 :(得分:2)

rangeChanged方法的Python版本:

scroll_area = QtGui.QScrollArea()
scroll_bar = scroll_area.verticalScrollBar()
scroll_bar.rangeChanged.connect(lambda: scroll_bar.setValue(scroll_bar.maximum()))

通过将rangeChanged方法连接到scrollldown,可以确保每次范围发生变化时滚动条都会向下滚动到最大值。

Source

答案 1 :(得分:1)

我遇到了同样的问题。我找到了一个解决方法,也可能对你有用。

在将小部件添加到滚动区域后立即使用scrollBar->setValue(scrollBar->maximum());时,使用pb_AdjustScrollBar不起作用。滚动条的最大值尚未更新。

但是,如果您有一个按钮,用户必须单击以将滚动条的位置调整到最大值,它才会起作用。似乎滚动区域仅异步(通过信号)通知其滚动条。所以我只是在我的小部件中添加了一个隐藏按钮animateClick(int),并在将小部件添加到滚动区域后使用clicked(bool)方法模拟了一次点击。收到AdjustScrollBar按钮的信号scrollBar后,我会触发scrollBarPtr->triggerAction(QAbstractSlider::SliderToMaximum); 以使用最大位置:

animateClick

注意:scrollBar超时必须设置为100ms(默认值)。将超时设置得更短会导致{{1}}不更新到其实际最大值。不过我猜100ms对用户交互来说足够快。

我仍然很想知道如何以更智能的方式解决这个问题。

答案 2 :(得分:1)

我找到了路。添加小部件后: view.requestFocusFromTouch();

答案 3 :(得分:1)

一种解决方法是使用垂直滚动条的rangeChanged(int,int)信号。

#include <QWidget>
#include <QBoxLayout>
#include <QScrollArea>
#include <QScrollBar>

class myClass
{
    Q_OBJECT
public:
    myClass();
private:
    QScrollArea *scrollArea;
    int scrollBarMax = 0;
private slots:
    void scrollToBottom(int min, int max);
};

myClass::myClass()
{
    QVBoxLayout *myLayout = new QVBoxLayout;
    QWidget *myWidget = new QWidget;
    myWidget->setLayout(myLayout);
    scrollArea = new QScrollArea;
    scrollArea->setWidget(myWidget);
    scrollArea->setWidgetResizeable(true);

    QObject::connect(scrollArea->verticalScrollBar(), SIGNAL(rangeChanged(int,int)), this, SLOT(scrollToBottom(int,int)));
}

void myClass::scrollToBottom(int min, int max)
{
    (void) min;
    if (max > scrollBarMax) scrollArea->verticalScrollBar()->setValue(max);
    scrollBarMax = max;
}

答案 4 :(得分:0)

嗯,我没有答案和同样的问题。然而,我可以提供一个小的再现示例:

#include <QtGui>

class TestWidget : public QWidget
{
    Q_OBJECT

public:
    TestWidget(QWidget * parent = 0);

private slots:
    void addButton();

private:
    QScrollArea * scrollArea;
    QWidget * contents;
    QVBoxLayout * contentsLayout;
};

TestWidget::TestWidget(QWidget * parent)
    : QWidget(parent)
{
    QVBoxLayout * layout = new QVBoxLayout(this);
    scrollArea = new QScrollArea(this);
    layout->addWidget(scrollArea);

    contents = new QWidget(this);
    scrollArea->setWidget(contents);
    contents->resize(300,400);
    scrollArea->setWidgetResizable(true);

    contentsLayout = new QVBoxLayout(contents);
    for (int i = 0; i < 10; ++i)
    {
        QPushButton * button = new QPushButton(QString("button %1").arg(i), this);
        connect(button, SIGNAL(clicked()), this, SLOT(addButton()));
        contentsLayout->addWidget(button);
    }

}

void TestWidget::addButton()
{
    QPushButton * button = new QPushButton("button", this);
    connect(button, SIGNAL(clicked()), this, SLOT(addButton()));
    contentsLayout->addWidget(button);
    QScrollBar * scrollBar = scrollArea->verticalScrollBar();
    scrollBar->setValue(scrollBar->maximum());
}

int main(int argc, char * argv[])
{
    QApplication app(argc, argv);

    TestWidget widget;
    widget.show();

    app.setQuitOnLastWindowClosed(true);

    return app.exec();
}

#include "main.moc"

问题发生在Qt 4.8和5.2(需要对示例进行微小修改)。

答案 5 :(得分:0)

有同样的问题,这是手册说的:

"In such cases, setting the layout's size constraint property to one which provides 
constraints on the minimum and/or maximum size of the layout (e.g., 
QLayout::SetMinAndMaxSize) will cause the size of the scroll area to be updated 
whenever the contents of the layout changes."

在我的情况下,QScrollArea的内容大小是通过QScrollArea的小部件的setMinimumSize方法更改的,所以我只添加了ui->scroll_area->widget()->layout()->setSizeConstraint(QLayout::SetMinAndMaxSize);,它开始工作正常。

重要:调整QScrollArea的小部件的大小之后,应在自定义事件处理程序内更改QScrollBar的值。简单的例子:

bool MyCustomClassWithScrollArea::event(QEvent * event)
{
    switch (event->type())
    {
        case MyCustomScrollToEndEvent::ScrollToEndEventType:
        {
            ui->scroll_area->verticalScrollBar()->setValue( ui->scroll_area->verticalScrollBar()->maximum() ); //scrolls to the end
            return true;
        }
    }

    return QWidget::event(event);
}