在QT QML中,如何在窗口管理器完成调整窗口大小时获取信号?

6
我试图实现与macOS上iTunes的miniPlayer相似的效果。也就是说,检测窗口大小调整完成后再改变高度到某个值。这里有一个视觉示例:enter image description here 问题在于,在QML窗口中没有信号可以通知我窗口管理器何时调整大小完成(即用户释放句柄)。因此,如果我没有信号并且在调整大小期间立即应用高度更改,窗口将闪烁(双重调整大小发生),只要用户没有释放句柄。
感谢任何帮助或输入!

您能添加一些此效果的视觉示例(gif)吗? - magrif
我刚刚添加了它! - N.D.
尝试在C++端进行此操作:https://stackoverflow.com/questions/51223199/get-size-of-applicationwindow-in-c - bardao
不,我不需要窗口的大小,而是用户释放窗口的时刻,而不是在调整大小但未释放窗口时的时刻。 - N.D.
OP,你找到内置的解决方案了吗? - Curtwagner1984
4个回答

3

你可以使用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
        }
    }
}

1
非常感谢。我认为你的答案在Qt中似乎更为可行。不过,这仍然非常混乱,因为这意味着失去所有系统优势(快速切换窗口,角落调整大小等)。我会先尝试这种方法,但不会将你的答案标记为解决我的问题,因为它仍然不是完美的,“尽可能接近本地”的解决方案。 - N.D.

0

QML提供了一些NOTIFY信号,当属性值需要更新时使用。因此您可以使用Window.widthWindow.height

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
}

谢谢您的回答,但这根本没有解决我的问题。事实上,我已经尝试过这种方法,但我特别需要一个信号来告诉我用户何时释放句柄。因为如果我强制调整窗口大小,一旦用户停止调整大小但仍然保持拖动句柄,并且稍后决定再次更改位置,调整大小将会改变句柄位置,新的调整大小将再次将窗口大小更改为(最后)保持的位置。最终结果在视觉上非常不愉快! - N.D.

0

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

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

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

    • 如果是,则假定用户仍然持有窗口调整大小句柄,因此不要调整窗口高度。
    • 如果不是,则假定用户释放了窗口调整大小句柄并开始自由移动光标。现在调整窗口高度。

您可能需要克服几个问题,例如(1)允许窗口高度和光标y位置变化之间的一定差异,因为窗口高度变化可能不太频繁并且在某种程度上追踪光标移动,(2)仅在窗口调整大小期间启用光标位置事件处理程序以限制系统负载。但如果它起作用,那么它是一种本地解决方案,不需要实现自己的调整大小句柄。


0
似乎您希望QML发送两种不同类型的信号,一种用于标记调整大小的开始和结束,另一种用于标记调整大小期间的大小变化。事件序列将类似于以下内容:
window.resizeStarted() // hypothetical new event

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

window.resizeEnded()   // hypothetical new event

这在Qt中似乎是不可能的,但您可以使用以下方法自己实现,最初意味着在调整大小时根本不重新绘制窗口:

过滤相关事件,直到鼠标按钮被释放。具体来说,在鼠标按下时“吃掉”调整大小事件,然后在鼠标释放时合成最终的调整大小事件。您可以在附加到显示QML界面的窗口/小部件对象的事件过滤器中完成所有操作。(source

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

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

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

  3. 在 QML 中实现相应的信号处理程序 onResizeEnded 来适应您的应用程序窗口高度到某个固定值。

对我来说似乎是一个相当有前途的路线,但需要注意的是,到目前为止我还没有在代码中尝试过它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接