在 qml 中拖动无框窗口“抖动”

Posted

技术标签:

【中文标题】在 qml 中拖动无框窗口“抖动”【英文标题】:Dragging frameless window "jiggles" in qml 【发布时间】:2016-08-22 21:15:39 【问题描述】:

我有一个无框架的 ApplicationWindow,我想使用this 问题的答案使其可拖动。然而,正如有人在评论中所说,当我快速移动窗口时,它会抖动很多

我一直在尝试改进它,但没有成功。

ApplicationWindow 
    visible: true
    width: 640
    height: 480
    title: qsTr("WIP")
    id: mainWindow
    flags: Qt.SubWindow | Qt.Tool | Qt.FramelessWindowHint | Qt.WindowSystemMenuHint
    header: ToolBar

        MouseArea
            anchors.fill: parent
            onDoubleClicked: mainWindow.visibility!="2"?mainWindow.showNormal():mainWindow.showMaximized()
            id: maMainWindow
            property variant clickPos: "0,0"

            onPressed: 
                clickPos  = Qt.point(mouse.x,mouse.y)
            

            onPositionChanged: 
                    var delta = Qt.point(mouse.x-clickPos.x, mouse.y-clickPos.y)
                    mainWindow.x += delta.x;
                    mainWindow.y += delta.y;
            
        
    

如果我添加标签和一些元素,情况会变得更糟。

C++ 能否以某种方式提高其性能?

【问题讨论】:

导入QtQuick.Window 可能有助于Window.Visibility 枚举。 根据 relative 提供的按下和移动坐标计算 全局 窗口坐标的增量听起来不是一个好主意鼠标区域。如果下面的窗户一移动,事情就会向南移动,我并不感到惊讶。 :) 我正在导入 QtQuick.Window 2.0,但我不明白使用可见性枚举是什么意思。您可以添加一个替代方法来计算全局窗口的增量吗? 【参考方案1】:

我遇到了同样的问题,性能还可以,但是在 linux 上它在整个屏幕上跳跃并“抖动”。我已经通过在 C++ 中编写一个帮助程序类来解决它,我已经将它公开为 QML 上下文属性。这个解决方案对我帮助很大。我有非常复杂的用户界面,它工作得非常好,性能非常好。 所以让我们开始吧。 1) 你需要一个类似这样的辅助类:

class CursorPosProvider : public QObject

    Q_OBJECT
public:
    explicit CursorPosProvider(QObject *parent = nullptr) : QObject(parent)
    
    
    virtual ~CursorPosProvider() = default;

    Q_INVOKABLE QPointF cursorPos()
    
        return QCursor::pos();
    
;

这是一个非常简单的类,它只从 C++ 端为您提供光标位置,这很奇怪,但是当您在 QML 中执行相同操作时,您会遇到问题(至少在 linux 上)。 2) 将其作为上下文属性公开给 QML 引擎,我已经通过以下方式完成了:

int main(int argc, char *argv[])

    QGuiApplication app(argc, argv);

    QQuickView view;

    CursorPosProvider mousePosProvider;

    view.rootContext()->setContextProperty("mousePosition", &mousePosProvider);

    view.setSource(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();

3) 好的,现在我们已经准备好使用 QML 部分了。 我有一个 Qt Quick 组件,它为无框窗口实现了 TitleBar,如下所示:

Rectangle 
    id: root
    width: parent.width
    color: "#0099d6" // just random one

    property QtObject container

    // extra properties, maybe some signals

    MouseArea 
        id: titleBarMouseRegion
        property var clickPos
        anchors.fill: parent
        onPressed: 
            clickPos =  x: mouse.x, y: mouse.y 
        
        onPositionChanged: 
            container.x = mousePosition.cursorPos().x - clickPos.x
            container.y = mousePosition.cursorPos().y - clickPos.y
        
    

4) 现在你可以在任意窗口中使用这个 TitleBar 了:

Window 
    id: root
    visible: true

    flags: Qt.FramelessWindowHint

    TitleBar 
        height: 20
        container: root
    

    Text 
        text: qsTr("Hello World")
        anchors.centerIn: parent
    

当我为标题栏实现拖放时,主要问题是 QML 提供的绳索,这个解决方案解决了这个问题。 如果我的解决方案对您有帮助,请提供一些反馈。我真的很感兴趣:)

【讨论】:

【参考方案2】:

我认为您无能为力,这只是使用绑定构建 GUI 的副作用,并且绑定评估与渲染不同步。结果,当您移动或调整窗口大小时,一切都像弹性一样摇摆不定,直到值“赶上”。这是 QML 的事情,在小部件中你不会得到那种行为,因为 UI 不是围绕绑定构建的。基本上,每个绑定链的评估都存在延迟,当 GUI 绘制时,它会捕获并显示绑定链传播的延迟,链中的第一个对象已经在它们的新位置,而那些更远的向后可以在传播中落后几个步骤。当然,您的窗户是否有框架与该问题完全无关。

克服这一点需要控制绑定如何处理信号,我认为目前没有这样的事情。基本上,诀窍是以某种方式强制绘制等到链中的每个绑定都被评估,并在启动另一系列评估之前绘制。

自然,您拥有的元素越多,每次更改将级联所有这些元素所需的时间就越长,从而使效果更加明显。它还取决于您的系统有多快——因为这决定了评估绑定链的延迟,例如我的系统很快,而您的示例代码不会产生抖动。然而,虽然在调整大小期间发生这种情况是可以理解的,但它引出了一个问题,为什么当您只是移动窗口时会发生这种情况。毕竟,这不应该真正改变窗口中 UI 元素的相对位置。我怀疑发生这种情况是因为在内部这些对象是在“绝对屏幕空间”中绘制的,因此当您移动窗口时,这会导致每个元素的实际绝对位置发生变化,即使它们相对于窗口保持在同一位置,从而导致这种行为。不理想...不仅引入了不受欢迎的视觉行为,而且还引入了许多额外的评估,这些评估似乎是不必要的开销。

请注意,这些只是我的模糊怀疑,我没有详细调查此事,希望有人可以提供一种快速简便的方法来处理这个问题。现在我忽略了这个问题,希望它不会太烦人,考虑到我关注的软件不是关于窗口位置和几何形状的连续变化;)顺便说一句,即使我第一次在 QML 中看到这个,在过去的几年里,我确实在其他“现代 gui”框架中也注意到了它。这是可以理解的,因为这些框架为了快速原型设计而转向性能较慢的语言,并结合“流畅”的异步非阻塞渲染。

【讨论】:

使用我帖子的代码,它会稍微抖动,但如果我添加一些元素,性能就会下降。让我们希望其他人已经找到了改善这种行为的方法。 绑定不是异步的。 @jpnurmi 我没有正确用词,我的意思是它与渲染不同步。

以上是关于在 qml 中拖动无框窗口“抖动”的主要内容,如果未能解决你的问题,请参考以下文章

qml无框窗口的阴影

在 qml 中恢复最小化的无框窗口

在电子 14 和 15 的无框窗口中拖动不起作用

JAVA_swing抖动窗口,要求在拖动窗口位置后能在新位置进行抖动!请看代码...

如何在不使用 -webkit-app-region 的情况下在 Electron 中移动无框窗口

为啥在调试过程中有时窗口标题为黑色和按钮无框