我需要知道我的QTableWidget
的verticalScrollBar
何时显示。 我目前正在使用以下说明:
页眉:
#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))