如何知道垂直滚动条何时显示?



我需要知道我的QTableWidgetverticalScrollBar何时显示。 我目前正在使用以下说明:

页眉:

#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

填充表功能:

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
}

输出:

// 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

但它返回一个错误的值。当滚动条可见时,它返回 false,当它不可见时,它返回 true。注意:myTableWidget (QTableWidget) 始终可见。

还有其他方法可以做到这一点吗?

我正在使用Qt版本5.3.2

一般来说,你使用的代码应该可以工作 - 在Qt 5.3.0上检查。

但是,您必须确保在进行调用时,QTableWidget本身是可见的。

例如,如果您在MainWindow构造函数中进行调用,您肯定会得到false答案。只有在显示表单后,在特定滚动条上调用isVisible()才会返回正确的值。

编辑:

粘贴您的代码后,我能够重现该问题。我需要稍微浏览一下Qt代码,看看发生了什么。基本上事实证明,对于QTableView的父类QTableWidget滚动条值是通过updateGeometries更新的(不要将其与常规updateGeometry混淆,我提到的是protected)。在内部,直接调用此方法或通过事件循环处理事件。简而言之,这取决于您是添加列还是行。

在您的示例中,如果您在检查horizontalScrollBar可见性后insertColumn而不是insertRow(并在setItem中切换参数),您将立即获得正确的结果。

我可以通过子类化QTableWidget并覆盖event方法来确认这一点。它显示添加列时会执行以下事件:MetaCall(调用调用)和LayoutRequest。另一方面,当添加行时,传递的第一个事件是Timer

我不是Qt实现者,所以我不确定区别的目的是什么。但是,此信息有助于以更优雅的方式解决问题。

您可以实现覆盖event方法的MyTableWidget

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();
}

但是,此类事件可能会在其他情况下被调用,不仅当由于模型数据更新而需要更新视图时。

另一种解决方案是避免重写event方法,而是创建自己的方法来触发所需的更新。例如:

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

这将直接调用updateGeometries,重新计算滚动条最小/最大值,并对LayoutRequest执行直接event方法调用(不通过 eventloop 进行处理)。如果我是正确的,间接更新滚动条可见性。

在检查可见性之前调用此方法也应该可以解决问题。

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

我想在QScrollBar可见时通过信号得到通知。我在这里写这个答案,因为这是我得到的第一个谷歌结果,没有结果有正确的答案。

首先,没有改变可见性的信号,因此我们将使用valueChanged.

现在你可以添加一个函数来检查滚动条是否isVisible().
问题:它不起作用(对Qt有更多了解的人可能会解释为什么,可惜我不能)。

诀窍是,使用QTimer(Python代码):

self.horizontalScrollBar().valueChanged.connect(lambda x: QTimer.singleShot(0, some_func))

最新更新