window 管理器在 qt QML 中完成 window 大小调整后如何获得信号?

How to get a signal when window manager is done resizing window in qt QML?

我正在尝试在 macOS 上调整大小时实现与 iTunes 的 miniPlayer 类似的效果。也就是说,检测 window 的大小调整何时完成,然后将高度更改为特定值。这是一个视觉示例:

问题是当 window 管理器完成大小调整(即用户释放句柄)时,QML window 中没有信号通知我。因此,如果我没有信号并在调整大小时宽度或高度发生变化时立即应用我的高度变化,只要用户没有释放手柄,window 就会闪烁(发生双重调整) .

感谢任何输入或帮助!

您可以很容易地实现自己的调整大小手柄,使用 MouseArea 并使用 onReleased 处理最终调整大小计算(此处强制高度为释放时宽度的 75%):

Window {
    id: window
    flags: Qt.FramelessWindowHint
    visible: true
    height: 300
    width: 400

    MouseArea {
        id: resize
        anchors {
            right: parent.right
            bottom: parent.bottom
        }
        width: 15
        height: 15
        cursorShape: Qt.SizeFDiagCursor

        property point clickPos: "1,1"

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

        onPositionChanged: {
            var delta = Qt.point(mouse.x-resize.clickPos.x, mouse.y-resize.clickPos.y)
            window.width += delta.x;
            window.height += delta.y;
        }

        onReleased: {
            window.height = .75 * window.width
        }

        Rectangle {
            id: resizeHint
            color: "red"
            anchors.fill: resize
        }
    }
}

QML 在应该更新 属性 值时提供了一些 NOTIFY 信号。所以你可以使用 Window.width's 和 Window.height's:

Window {
    id: window

    onWidthChanged: {
        // Will be executed after window.width value changes.
    }

    onHeightChanged: {
        // Will be executed after window.height value changes.
    }

    // Other window-related stuff
}

这是一个想法(我还没有尝试过,但仍然如此):

  1. 实现一个事件处理程序来响应全局光标位置的变化。 window 内的光标位置不适用,因为抓住调整大小手柄时光标位于 window 之外。不确定这样的事件处理程序是否可行以及如何实现,但至少访问屏幕全局光标位置是 possible in Qt.

  2. 在事件处理程序中,检查与上次处理程序调用相比的垂直光标位置变化是否与 window 高度变化相同。

    • 如果是,假设用户仍然持有window调整大小手柄,所以不适应window高度。
    • 如果不是,则假设用户释放了 window 调整大小手柄并开始自由移动光标。现在调整 window 高度。

您可能必须克服几个问题,例如 (1) 允许 window 高度和光标 y 位置变化之间存在一定差异,因为 window 高度变化可能较小频繁并稍微跟踪光标移动,(2) 仅在 window 调整大小时使用光标位置事件处理程序以限制系统负载。但如果它有效,它就是一个本机解决方案,而不是实现自己的调整大小句柄。

您似乎希望 QML 发送两种不同的信号类型,一种标记调整大小的开始和结束,另一种标记调整大小期间的大小变化。事件序列将是这样的:

window.resizeStarted() // hypothetical new event

window.widthChanged()
window.heightChanged()
window.widthChanged()
window.heightChanged()
...

window.resizeEnded()   // hypothetical new event

在开箱即用的 Qt 中这显然是不可能的,但是您应该能够使用这种方法自己实现它,最初的意思是在调整大小时完全不重绘 window:

Filter the relevant events out until the mouse button has been released. Specifically, "eat" the resize event while the mouse button is held down, and then synthesize the final resize event once the mouse is released. You can do it all in an event filter attached to the window / widget object that displays your QML interface. ()

这个过程与引用中的过程非常相似:

  1. 使用自定义信号扩展 QML Window 类型:

    //MyWindow.qml
    Window {
       signal resizeStarted()
       signal resizeEnded()
    }
    
  2. 在 QML window 上创建一个“吃掉”所有 window 调整大小事件的事件过滤器。当它遇到第一个时,它发送resizeStarted()。然后它转发 window 调整大小事件。当它在调整大小时遇到​​鼠标释放事件时,它会在最后一个 widthChanged() / heightChanged() 事件之后发送 resizeEnded()

  3. 在QML中实现一个相应的信号处理器onResizeEnded来响应,这里是为了让你的应用程序window的高度适应某个固定值。

对我来说似乎是一条很有前途的路线,但请注意,到目前为止我还没有在代码中尝试过。