问题描述
我现在正在开发一个简单的QML
应用程序,我注意到与QtWidgets
窗口相比,调整大小和移动QML
窗口会产生难看的闪烁.
I'm developing a simple QML
application right now and I noticed that resizing and moving a QML
window generates an ugly flicker compared to a QtWidgets
window, for instance.
因此,我创建了2个测试应用程序以显示差异:
So I created 2 test applications to show the difference:
Q小部件:
QML:
如您所见,当QtWidgets
干净时,应用程序的QML
版本会闪烁得很丑.现在,当您的UI变得越来越复杂时,这变得非常难看.
As you can see the QML
version of the application flickers pretty ugly while the QtWidgets
one is clean. Now this gets pretty ugly when your UI grows in complexity.
您对此有任何了解吗?这是一个错误吗?是否有针对此问题的任何修复/解决方法?
Do you have any knowledge about this? Is this a bug? Is there any fix/workaround for this issue?
推荐答案
调整QML应用大小的问题在于更新具有过时几何形状的窗口.解决方法是同步更新并调整大小.
The issue with resizing of QML apps is about updating a window with outdated geometry. The fix would be to sync the updates and resizing.
由于从更新计时器到渲染场景图可能会突然进行更新,因此可以随时更新窗口,因此会导致绘制几何形状已过时的内容. https://bugreports.qt.io/browse/QTBUG-46074
Since there might be sudden updates from update timer to render scene graph, which can update the window at any time, it causes drawing of the content with outdated geometry.https://bugreports.qt.io/browse/QTBUG-46074
应使用基本同步或扩展同步来同步调整大小和窗口更新.当前,基本同步已在Qt中使用和实现,但仍需要将窗口更新(来自计时器)与Windows Manager中调整事件的大小进行同步.
Either Basic or Extended synchronization should be used to synchronize resizing and the window updates.Currently Basic sync is used and implemented in Qt, but still need to synchronize the window updates (from timer) with resizing events from Windows Manager.
但是,一如既往,有一系列问题:
But, as always, there is a list of issues:
当窗口调整大小的速度过快时,会出现此问题.由于同步事件(来自WM)应始终发送,因此在上一个之后的下一个:
The problem is observed when the window is being resizing too fast.Since sync events (from WM) should be sent consistently, next after previous:
-
< = = _NET_WM_SYNC_REQUEST是从WM发送的,大小现在正在更改.
<= _NET_WM_SYNC_REQUEST is sent from WM, the size is changing now.
_NET_WM_SYNC_REQUEST由应用程序接收和处理.
_NET_WM_SYNC_REQUEST is received and handled by app.
< ==收到了其他一些事件,例如新的几何图形.
<= some other events received, like new geometry.
..更新内容,swapBuffers.
.. update the content, swapBuffers.
=>将_NET_WM_SYNC_REQUEST_COUNTER发送回WM.
=> Sent _NET_WM_SYNC_REQUEST_COUNTER back to WM.
< = _NET_WM_SYNC_REQUEST从WM重新发送,大小正在更改.
<= _NET_WM_SYNC_REQUEST is sent again from WM, the size is changing.
.. swapBuffers //这是问题所在,当窗口更改其几何形状时执行更新.
.. swapBuffers // here is the problem, the update is performed when the window is being changing its geometry.
_NET_WM_SYNC_REQUEST已接收并再次处理.
_NET_WM_SYNC_REQUEST received and handled again.
因此,当_NET_WM_SYNC_REQUEST发送但尚未接收/处理后出现(7)个swapBuffers时,就会发生此问题.
So the issue happens when (7) swapBuffers appears after _NET_WM_SYNC_REQUEST is sent but not received/processed yet.
最后得出结论:
- 窗口管理器发送_NET_WM_SYNC_REQUEST 后立即开始实际调整窗口大小.,而不是在应用程序收到窗口时.发送同步请求时,窗口甚至可以在此时进行更新,但尚未由应用处理.它将使用过时的几何图形绘制内容.
- _NET_WM_FRAME_DRAWN可以帮助在调整大小和更新之间进行同步,但窗口管理器"可能不支持(并且可能不支持).
- Actual resizing of the window is started right after _NET_WM_SYNC_REQUEST is sent by The Window Manager. And not when the app receives it. The window could be even updated at this time, when sync request is sent, but not handled by the app yet. Which will draw the content with outdated geometry.
- _NET_WM_FRAME_DRAWN could help to sync between resizing and updates, but also might not be supported (and guess it is not) by The Window Manager.
换句话说,基本同步或扩展同步都无济于事(至少没有_NET_WM_FRAME_DRAWN),因为无法知道何时实际调整大小.
In other words, either basic or extended synchronization does not help, (at least without _NET_WM_FRAME_DRAWN), because there is no way to know when actual resizing is done.
扩展同步协议是尝试解决此问题的方法,但是,正如我所看到的,由于几何形状的实际更改是在不与客户端同步的情况下完成的,因此,如果没有_NET_WM_FRAME_DRAWN,总是有机会使用过时的几何形状来更新窗口.
Extended sync protocol is a try to handle this, but since actual changing of geometry is done without syncing with the client, as I can see, without _NET_WM_FRAME_DRAWN there is always a chance to update the window with outdated geometry.
https://lists.freedesktop.org/archives/xcb/2019-February/011280.html
这篇关于QML窗口大小调整/移动闪烁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!