如何知道用户何时完成调整 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.
来支持它
解决方案
我解决此类问题的方法是:
- 在调整大小发生之前采取行动
正如@musicamante 在评论中所写:
When you receive a resizeEvent the resizing has already happened
超车方式QWidget::resizeEvent
is using QObject::event
instead and watch for QEvent::type
QResizeEvent
.
- 尝试区分 程序调整大小,即调用
QWidget::resize
和 用户调整大小,即通过拖动 [=82] =] 的边缘
QEvent::spontaneous
可用于此目的,因为它:
Returns true if the event originated outside the application (a system event); otherwise returns false.
如果事件是 non-spontaneous(程序调整大小),允许生成 resizeEvent
以设置复杂小部件的初始大小。对于自发事件(用户调整大小),防止生成 resizeEvent
并手动处理复杂小部件的大小
- 获取用户完成 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();
}
我正在为自己编写一个 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.
来支持它解决方案
我解决此类问题的方法是:
- 在调整大小发生之前采取行动
正如@musicamante 在评论中所写:
When you receive a resizeEvent the resizing has already happened
超车方式QWidget::resizeEvent
is using QObject::event
instead and watch for QEvent::type
QResizeEvent
.
- 尝试区分 程序调整大小,即调用
QWidget::resize
和 用户调整大小,即通过拖动 [=82] =] 的边缘
QEvent::spontaneous
可用于此目的,因为它:
Returns true if the event originated outside the application (a system event); otherwise returns false.
如果事件是 non-spontaneous(程序调整大小),允许生成 resizeEvent
以设置复杂小部件的初始大小。对于自发事件(用户调整大小),防止生成 resizeEvent
并手动处理复杂小部件的大小
- 获取用户完成 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();
}