在 qml 中拖动无框窗口"jiggles"

Dragging frameless window "jiggles" in qml

本文关键字:窗口 jiggles qml 拖动      更新时间:2023-10-16

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

我一直在努力改进它,但没有成功。

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++可以提高它的性能吗?

我遇到了同样的问题,性能还可以,但是在linux上它在屏幕上跳来跳去并且"抖动"。我通过在c++中编写一个助手类来解决这个问题,我已经将其暴露为QML上下文属性。这个解决方案对我帮助很大。我有一个非常复杂的UI,它工作得非常好,性能非常好。让我们开始吧。1)您将需要一个像这样的helper类:

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快速组件,实现了无框窗口的标题栏,像这样:

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
        }
    }
}
现在你可以在任意窗口中使用标题栏了
Window {
    id: root
    visible: true
    flags: Qt.FramelessWindowHint
    TitleBar {
        height: 20
        container: root
    }
    Text {
        text: qsTr("Hello World")
        anchors.centerIn: parent
    }
}

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

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

克服这个问题需要控制绑定处理信号的方式,我认为目前还没有这样的事情。基本上,技巧是以某种方式强制绘图等待,直到链中的每个绑定都被求值,并在启动另一系列求值之前进行绘图。

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

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