How to know when the VerticalScrollBar is showing?

烈酒焚心 提交于 2019-12-08 11:59:06

问题


I need to know when the verticalScrollBar of my QTableWidget is being shown. I am currently using the following instruction:

Header:

#ifndef MYCLASS_H
#define MYCLASS_H

#include <QDebug>
#include <QWidget>
#include <QScrollBar>

namespace Ui {
class MyClass;
}

class MyClass: public QWidget
{
    Q_OBJECT

public:
    explicit MyClass(QWidget *parent = 0);
    ~MyClass();

private:
    void populateTable(QVector<QString> content);

private:
    Ui::MyClass *ui;
};

#endif // MYCLASS_H

Populate table function:

void MyClass::populateTable(QVector<QString> content)
{
    while( ui->myTableWidget->rowCount() > 0 )
    {
        ui->myTableWidget->removeRow(0);
    }

    QTableWidgetItem* item;
    for (int row = 0; row < content.length(); ++row)
    {
        ui->myTableWidget->insertRow(row);

        item = new QTableWidgetItem( QString::number(row) );
        item->setTextAlignment(Qt::AlignCenter);
        ui->myTableWidget->setItem(row, 0, item);

        item = new QTableWidgetItem( content.at(row) );
        item->setTextAlignment(Qt::AlignCenter);
        ui->myTableWidget->setItem(row, 1, item);
    }

    qDebug() << "This : " << this->isVisible();
    qDebug() << "QTableWidget : " << ui->myTableWidget->isVisible();
    qDebug() << "VerticalScrollBar : " << ui->myTableWidget->verticalScrollBar()->isVisible(); // <-HERE
}

Output:

// Called from the constructor
This :  false
QTableWidget :  false
VerticalScrollBar :  false

// Called by a button pressed
This :  true
QTableWidget :  true
VerticalScrollBar :  true
This :  true
QTableWidget :  true
VerticalScrollBar :  false

But it returns a wrong value. When the ScrollBar is visible it returns false and when it is not visible it returns true. Note: myTableWidget (QTableWidget) is always visible.

Is there any other way that I can do this?

I'm using Qt version 5.3.2


回答1:


In general the code you are using is supposed to work - checked on Qt 5.3.0.

However, you must be sure that when you are making the call the QTableWidget itself is visible.

For example if you make the call inside the MainWindow constructor you will certainly get a false answer. Only after the form is shown the call to isVisible() on particular scrollbar would return the correct value.

EDIT:

With your code pasted I was able to reproduce the issue. I needed to go through the Qt code a bit to see whats going on. Basically it turns out that for QTableView which is parent class of QTableWidget scroll bar values are updated via updateGeometries (do not confuse it with the regular updateGeometry the one I'm mentioning is protected). Internally this method is called either directly or the event is processed through the event loop. In short, it depends on whether you add columns or rows.

In your example, if you insertColumn instead of insertRow (and switch the arguments in setItem) after checking the visibility of horizontalScrollBar you will get the proper result right away.

I could confirm this by subclassing the QTableWidget and overriding event method. It shows that when adding columns following events are executed: MetaCall (invoke call) and LayoutRequest. On the other hand, when adding rows first event passed is Timer.

I'm not Qt implementer so I'm not sure what is the purpose the difference. However, this info helps solving your problem in a more elegant way.

You can implement MyTableWidget which overrides the event method.

class MyTableWidget: public QTableWidget
{
    Q_OBJECT
public:
    bool event(QEvent *e) override
    {
        const bool result = QTableWidget::event(e);
        if (e->type() == QEvent::LayoutRequest)
        {
            // call what you need here
            // or emit layoutUpdated(); and connect some slots which perform
            // processing dependent on scrollbar visibility
        }
        return result;
    }

signals:
    void layoutUpdated();
}

However, such event might get called in other situations not only when the view needs to be updated due to model data updates.

Another solution would be to avoid overriding the event method but creating your own method to trigger the required updates. For example:

void MyTableWidget::updateLayout()
{
    QEvent ev{QEvent::LayoutRequest};
    QTableWidget::updateGeometries();
    QTableWidget::event(&ev);
}

This would call directly updateGeometries which recalculates scrollbar min/max values and perform a direct event method call for LayoutRequest (without processing through eventloop). Which if I'm correct indirectly updates scrollbar visibility.

Calling this method before checking the visibility should also fix your problem.

ui->myTableWidget->updateLayout();
qDebug() << "VerticalScrollBar : " << ui->myTableWidget->verticalScrollBar()->isVisible();
// prints "VerticalScrollBar :  true   false"


来源:https://stackoverflow.com/questions/41271364/how-to-know-when-the-verticalscrollbar-is-showing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!