如何知道用户何时完成调整 window 的大小?

How to know when the user has finished resizing the window?

我正在为自己编写一个 PDF Reader 来娱乐和咯咯地笑,但是当 window 正在调整大小时我遇到了麻烦。问题如下:当加载 PDF 时调整 window 大小时,将再次呈现 PDF 以匹配新的 window 大小,但是 resizeEvent 被调用多次,因此渲染函数被称为多次,这是非常低效的并且会导致滞后。有没有办法让程序在 resizeEvent 完全完成时发出通知,然后调用渲染函数?欢迎使用 Python 和 C++ 的解决方案

假设您的 class 被命名为 PDF_reader 您可以使用 single-shot QTimer 在特定时间长度内未调整小部件大小时通知您-- 比如说 1 秒 -- 并且仅在该计时器处于非活动状态时才更新小部件。

一个基于 QLabel 的简单示例可能类似于...

class PDF_reader: public QLabel {
  using super      = QLabel;
  using this_class = PDF_reader;
public:
  PDF_reader ()
    : super("Some text goes here")
    {
      m_timer.setSingleShot(true);
      m_timer.setInterval(1000);
      connect(&m_timer, &QTimer::timeout, this, [this]{ update(); });
    }
  virtual void resizeEvent (QResizeEvent *event) override
    {
      m_timer.stop();
      m_timer.start();
    }
  virtual void paintEvent (QPaintEvent *event) override
    {
      if (!m_timer.isActive()) {
        super::paintEvent(event);
      }
      event->accept();
    }
private:
  QTimer m_timer;
};

免责声明

下面的解决方案是对问题 如何知道用户何时完成 window 的大小调整? 的回答,这个问题很清楚,可以回答。

但是,我相信您遇到了 XY 问题。您遇到的缓慢渲染可能是由于使用了错误的技术,但如果不看代码就无法判断。我建议你在另一个问题中描述你的渲染问题,用 Minimal, Reproducible Example.

来支持它

解决方案

我解决此类问题的方法是:

  1. 在调整大小发生之前采取行动

正如@musicamante 在评论中所写:

When you receive a resizeEvent the resizing has already happened

超车方式QWidget::resizeEvent is using QObject::event instead and watch for QEvent::type QResizeEvent.

  1. 尝试区分 程序调整大小,即调用 QWidget::resize用户调整大小,即通过拖动 [=82] =] 的边缘

QEvent::spontaneous 可用于此目的,因为它:

Returns true if the event originated outside the application (a system event); otherwise returns false.

如果事件是 non-spontaneous(程序调整大小),允许生成 resizeEvent 以设置复杂小部件的初始大小。对于自发事件(用户调整大小),防止生成 resizeEvent 并手动处理复杂小部件的大小

  1. 获取用户完成 window 大小调整的 确切 时刻,而不是使用计时器,如 @G.M。 (顺便说一下,我非常尊重)建议

这里 NonClientAreaMouseButtonRelease 事件类型可能会派上用场。

这并不一定意味着用户正在调整 window 的大小。此事件类型的生成也被拖动window。但是,在这种情况下,这并不影响解决方案。

注意:不要将复杂的小部件添加到任何布局,因为它会破坏手动大小处理。

示例

这是我为您编写的 C++ 示例,用于演示如何实施建议的解决方案:

#include <QApplication>
#include <QResizeEvent>
#include <QFormLayout>
#include <QLineEdit>

class MainWindow : public QWidget
{
    QWidget *m_complexWidget;
public:
    MainWindow(QWidget *parent = nullptr) :
        QWidget(parent),
        m_complexWidget(new QWidget(this)) {
        auto *form = new QFormLayout(m_complexWidget);

        for (int n = 0; n < 20; n++)
            form->addRow(tr("Property ") + QString::number(n),
                         new QLineEdit(this));

        resize(400, 400);
    }

    bool event(QEvent *event) override {
        switch (event->type()) {
        case QEvent::NonClientAreaMouseButtonRelease:
            // The widget is resized at the end of a resize
            m_complexWidget->resize(size());
            break;
        case QEvent::Resize:
            // Prevent generation of a resize event
            if (event->spontaneous())
                return false;
            break;
        default:
            break;
        }

        return QWidget::event(event);
    }

protected:
    void resizeEvent(QResizeEvent *event) override {
        // The widget's size is set to the initial size of the window
        m_complexWidget->resize(event->size());
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;

    w.show();

    return a.exec();
}