我想知道小部件在哪些情况下会收到它的绘制事件,以及它如何随操作系统而变化。
paintEvent的Qt文档只说
绘制事件是重新绘制全部或部分窗口小部件的请求。它可能由于以下原因之一而发生:
调用了repaint()或update(),
小部件被遮挡,现在已被发现,或
许多其他原因。
到目前为止,我在paintEvent中添加了一些痕迹,
void Widget::paintEvent(QPaintEvent *e)
{
static int count = 0;
qDebug("paintEvent, %d", count++);
}
这就是我发现的(至少在Windows 7上):
当窗口小部件失去/获得焦点时,将调用paintEvent。当另一个窗口小部件通过我们的窗口小部件时,不会调用paint事件 。我不知道是不是因为Windows 7合成。恢复最小化窗口时也会调用paintEvent。调整大小时调用paintEvent。
依赖于操作系统的行为是什么?
答案 0 :(得分:19)
是的,从您描述的意义上讲,它取决于操作系统。
桌面窗口管理器(DWM),在Windows Vista和7中找到,负责桌面组合的doohickey,Aero玻璃效果以及各种其他眼睛糖果的工作方式与之前使用的模型略有不同Windows版本。正如您所怀疑的那样,它会缓存窗口的位图,即使它们不可见,因为它们被另一个窗口遮挡了。这意味着它不需要你重绘它们(因此它不会引发绘制事件),因为它只能从缓存的位图中将它们blit。这不仅是每个应用程序重绘自身的潜在优化,它还允许DWM实现Aero Flip之类的东西,它使用它的缓存位图。
这个例外就像它一直是CS_SAVEBITS
类风格一样。如果DWM缓存的位图已失效(例如,因为您的窗口图像已更改),它将丢弃它并要求您重绘窗口。
通过关闭DWM合成(切换到“Windows Classic”主题)测试此理论,然后遮挡窗口以查看是否收到绘画事件。您应该像在所有以前版本的Windows中一样。
但更重要的是,您不应该依赖于以任何特定顺序接收油漆事件。 关于绘制事件应该假设唯一的事情是,当操作系统需要您重新绘制窗口时,您将收到一个。否则,它不会打扰您。我确信这就是为什么文档在这一点上含糊不清,超出可能的技术限制。
这就是逻辑不应该进入paint事件处理程序的原因。该方法应该负责的仅事物是通过其当前状态重新绘制窗口。那个州需要在其他地方拯救。此规则也是可交换的:您不应该在paint事件处理程序的外上进行任何绘制。
当然,你总是可以通过使窗口无效来强制一个绘制事件(我确定Qt有一个invalidate
或refresh
方法,检查文档),但这并不意味着将应用程序逻辑放在处理此事件的方法中是一个很好的模式。