【问题标题】:How to know when the VerticalScrollBar is showing?如何知道 VerticalScrollBar 何时显示?
【发布时间】:2016-12-21 20:27:24
【问题描述】:

我需要知道我的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

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

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

我使用的是 Qt 5.3.2 版

【问题讨论】:

  • 您的期望是错误的。返回的值是正确的。就这样。当您查询小部件时,它要么不可见,要么尚未隐藏。您必须重新设计代码以在适当的时间查询或停止,具体取决于没有记录为您期望的行为。
  • 这不是一个完整的例子。一个完整的例子是一个单文件的最小代码段,任何人都可以复制粘贴到main.cpp,编译和运行。最关键的是,您没有显示何时调用查询。您只是在告诉我们您期望其他东西,但是如果不查看代码,就无法知道您期望什么以及为什么要进行第二次猜测。
  • 实际上,我无法共享整个代码,而且我现在也没有太多时间来编写一个完整的示例来显示整个“情况”。还是谢谢。
  • 共享整个代码会很糟糕,因为整个事情是不必要的。 “代码转储”问题很糟糕。您应该展示一个重现问题的最小示例:这样从字面上删除任何代码都会使问题消失。这就是minimal的意思。

标签: c++ qt qtablewidget


【解决方案1】:

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

但是,您必须确保在拨打电话时,QTableWidget 本身是可见的。

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

编辑:

粘贴您的代码后,我能够重现该问题。我需要稍微检查一下 Qt 代码以了解发生了什么。基本上事实证明,QTableViewQTableWidget 的父类,滚动条值是通过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 方法调用(不通过事件循环进行处理)。如果我是正确的,这会间接更新滚动条的可见性。

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

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

【讨论】:

  • 谢谢,@Dusteh。填充 TableWidget 后,我​​在函数内部进行调用。我用一个完整的例子更新了这个问题。
  • MyClass 也是 QWidget 吗(似乎如此)?请另外验证并打印出qDebug() &lt;&lt; isVisible(); - 就在检查滚动条可见性的下方。让我们知道您得到了什么。
  • 是的。我更新了问题。每次调用insertRowsetItem 时,QTableWidget 可视化是否都会更新?如果没有,那么当我调用verticalScrollBar()-&gt;isVisible() 函数时,QTableWidget 可视化可能尚未更新。
  • 是的,这可能意味着并非所有内容都是最新的。在检查可见性之前尝试调用QApplication::processEvents();
  • 我试图在qDebug() 调用之前插入一条QApplication::processEvents(); 指令,但没有成功。但是,如果我在qDebug 之前插入QApplication::processEvents(); 指令两次,它将在verticalScrollBar()-&gt;isVisible() 中获得正确的值。我认为它与QTableWidget 可视化更新有关。有没有可能是 Qt 错误?
【解决方案2】:

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

首先,没有改变可见性的信号,所以我们将使用valueChanged

现在您可以添加一个函数来检查滚动条是否isVisible()
问题:它不起作用(并且对 Qt 有更多了解的人可能会解释原因,我很遗憾无法解释)。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多