我知道的唯一体面的方法是将事件过滤器附加到小部件,并过滤掉重绘事件。无论小部件多么复杂,它都可以工作 - 它可以有子小部件。
下面是一个完整的独立示例。但是,它带有一些警告,需要进一步开发才能完成。只有绘制事件被覆盖,因此您仍然可以与小部件进行交互,只是看不到任何效果。
鼠标点击、鼠标进入/离开事件、焦点事件等仍然会到达小部件。如果小部件依赖于在重绘时完成的某些事情,可能是由于在这些事件上触发了 update(),则可能会出现问题。
至少您需要一个 case 语句来阻止更多事件——比如鼠标移动和单击事件。处理焦点是一个问题:您需要将焦点移到链中的下一个小部件,如果小部件在获得焦点时被隐藏,并且每当它重新获得焦点时。
鼠标跟踪也引起了一些担忧,如果小部件之前正在跟踪,您可能想假装它丢失了鼠标跟踪。正确地模拟这需要一些研究,我不知道 Qt 呈现给小部件的确切鼠标跟踪事件协议是什么。
//main.cpp
#include <QEvent>
#include <QPaintEvent>
#include <QWidget>
#include <QLabel>
#include <QPushButton>
#include <QGridLayout>
#include <QDialogButtonBox>
#include <QApplication>
class Hider : public QObject
{
Q_OBJECT
public:
Hider(QObject * parent = 0) : QObject(parent) {}
bool eventFilter(QObject *, QEvent * ev) {
return ev->type() == QEvent::Paint;
}
void hide(QWidget * w) {
w->installEventFilter(this);
w->update();
}
void unhide(QWidget * w) {
w->removeEventFilter(this);
w->update();
}
Q_SLOT void hideWidget()
{
QObject * s = sender();
if (s->isWidgetType()) { hide(qobject_cast<QWidget*>(s)); }
}
};
class Window : public QWidget
{
Q_OBJECT
Hider m_hider;
QDialogButtonBox m_buttons;
QWidget * m_widget;
Q_SLOT void on_hide_clicked() { m_hider.hide(m_widget); }
Q_SLOT void on_show_clicked() { m_hider.unhide(m_widget); }
public:
Window() {
QGridLayout * lt = new QGridLayout(this);
lt->addWidget(new QLabel("label1"), 0, 0);
lt->addWidget(m_widget = new QLabel("hiding label2"), 0, 1);
lt->addWidget(new QLabel("label3"), 0, 2);
lt->addWidget(&m_buttons, 1, 0, 1, 3);
QWidget * b;
b = m_buttons.addButton("&Hide", QDialogButtonBox::ActionRole);
b->setObjectName("hide");
b = m_buttons.addButton("&Show", QDialogButtonBox::ActionRole);
b->setObjectName("show");
b = m_buttons.addButton("Hide &Self", QDialogButtonBox::ActionRole);
connect(b, SIGNAL(clicked()), &m_hider, SLOT(hideWidget()));
QMetaObject::connectSlotsByName(this);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Window w;
w.show();
return a.exec();
}
#include "main.moc"