如何强制Qt更新鼠标下的小部件?

时间:2017-04-30 14:39:07

标签: c++ qt

在Windows 7上具体,虽然我认为不重要。

我们都在无数的桌面应用程序中看到过这个问题,特别是那些不使用OS提供的控件的游戏:当屏幕在静止的鼠标光标下以编程方式改变时(与用户将光标移动到新的小部件相反),他们不同步。光标不会改变,或者小部件没有被绘制,因为它应该是光标在其中 - 显然小部件的mouse enter事件不会被触发。如果你在没有离开小部件的情况下稍微摇动一下鼠标,事情就会自行解决。

可悲的是,Qt 5.7分享了这个普遍存在的问题。我想到的第一个解决方案是将鼠标以编程方式移动到(0, 0)并通过Windows方式返回。但是,它不是跨平台的(ish)。有更好的想法吗?

2 个答案:

答案 0 :(得分:0)

我不知道您的问题是否仍然存在

您可以使用以下代码覆盖方法underMouse()

bool MyWidget::underMouse()
{
    return rect().contains(mapFromGlobal(QCursor::pos()));
}

拆分器调整面板大小时,肯定会触发其余面板中的事件moveEventresizeEvent。您所需要做的就是检查小部件是否位于鼠标下,然后手动调用enterEvent()

答案 1 :(得分:0)

我找到了两个解决方案。

第一个是一个简单的技巧:调用 widget->hide(),然后立即调用 widget->show()。这将根据小部件是否在鼠标光标下重新评估和更新小部件的视觉状态,即使光标没有移动。但我不会推荐这个解决方案,因为它可能有一些不需要的副作用。虽然我还没有遇到过。

第二种解决方案更好,因为它看起来不像黑客,而且可能没有任何副作用:

widget->setAttribute(Qt::WA_UnderCursor, qApp->widgetAt(QCursor::pos()) == widget);
widget->update();

假定代码是从小部件的父级调用的。但是你可以调整它并从任何其他地方调用它。注意:使用 QApplication::widgetAt() 比使用 widget->rect().contains() 更好,这是在另一个答案中建议的,因为在后一种情况下,我们会得到被其他小部件覆盖的小部件的误报。

真正复杂的是在代码中找到应该调用它的地方。因为小部件的运动可能有很多来源 - 与其父一起移动,父移动,调整大小,调整父大小,滚动等。这可能是实现它太复杂的原因标准 Qt 小部件库。在某些情况下,它可能是性能杀手。 (我的猜测)

只是为了展示我的用法:我正在移动一个包含许多子小部件的整个容器小部件。随后,在移动容器后,子小部件之一可能位于光标下方。所以我打电话:

containerWidget->move(dx, dy); // this moves the container
for (QWidget *child : containerWidget->findChildren<QWidget*>())
{
    child->setAttribute(Qt::WA_UnderMouse, qApp->widgetAt(QCursor::pos()) == child);
    child->update();
}