6

I'm trying to achieve a similar effect as iTunes' miniPlayer when resizing happens on macOS. That is, detecting when a resizing of the the window has been completed, THEN changing the height to a certain value. Here is a visual example :

enter image description here

The problem is that no signal in a QML window exists to notify me when the window manager is done resizing (that is, the user released the handle). Hence, if I don't have a signal and apply my height change as soon as width or height is changed during resizing, the window will flicker (double resize happens) as long as the user didn't release the handle.

Thanks for any input or help!

tanius
  • 14,003
  • 3
  • 51
  • 63
N.D.
  • 157
  • 1
  • 2
  • 10

4 Answers4

3

You could implement your own resize handle pretty easily, using a MouseArea and handling the final resize calculation using onReleased (here forcing the height to be 75% of the width on release):

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
        }
    }
}
fallerd
  • 1,512
  • 10
  • 15
  • 1
    Thank you very much. I think your answer is what would seem the more feasable in Qt. It still remains very hackysh as it means losing all system advantages (fast switch between windows, corner resizing, ...). I'll try this approch first but don't mark your answer as solving my question as it still isn't a perfect, "as close to native as possible" solution. – N.D. May 25 '19 at 10:38
0

QML provided some NOTIFY signals when property values are supposed to be updated. So you can use Window.width's and 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
}
air-dex
  • 4,130
  • 2
  • 25
  • 25
  • Thanks for the answer but that doesn' solve my problem at all. In fact, I already tried this aproch but I especially need a signal when the user RELEASE the handle. Since, if I force a resize of the window as soon as the user stopped resizing but didn't stop holding the drag handle and later desides to change the position again, the resize would have changed the handle position and a new resize will change the window size again to the (last) holding spot. The end result is visually very unpleasant ! – N.D. May 25 '19 at 10:33
0

Here is an idea (that I did not try yet, but still):

  1. Implement an event handler reacting to changes of the global cursor position. The cursor position inside the window is not applicable as the cursor is outside the window when grabbing a resize handle. Not sure if and how such an event handler is possible, but at least accessing the screen-global cursor position is possible in Qt.

  2. In the event handler, check if the vertical cursor position change compared to the last call of the handler is the same as the window height change.

    • If yes, assume that the user still holds the window resizing handle, so don't adapt window height.
    • If no, assume that the user released the window resizing handle and started to move the cursor around freely. Adapt the window height now.

You'll probably have to overcome several issues, such as (1) allowing for a certain divergence between the window height and cursor y position changes, as window height changes might be less frequent and trail the cursor movement somewhat, (2) engaging the cursor position event handler only during a window resize to limit system load. But if it works, it's a native solution, not implementing own resizing handles.

tanius
  • 14,003
  • 3
  • 51
  • 63
0

It seems you want QML to send two different signal types, one to mark the start and finish of resizing, and one to mark size changes during resizing. The event sequence would then be something like this:

window.resizeStarted() // hypothetical new event

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

window.resizeEnded()   // hypothetical new event

That is apparently impossible in Qt out of the box, but you should be able to implement it yourself with this approach, originally meant to not repaint the window at all while resizing:

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. (source)

The process would be very similar to the one in the quote:

  1. Extend the QML Window type with custom signals:

    //MyWindow.qml
    Window {
       signal resizeStarted()
       signal resizeEnded()
    }
    
  2. Create an event filter on the QML window that "eats" all window resize events. When it encounters the first one, it sends resizeStarted(). Then it forwards the window resize events. When it encounters a mouse release event while resizing, it sends resizeEnded() after the last widthChanged() / heightChanged() event.

  3. Implement a corresponding signal handler onResizeEnded in QML to react, here to adapt the height of your application window to a certain fixed value.

Seems quite a promising route to me, but to note, I haven't tried it in code so far.

tanius
  • 14,003
  • 3
  • 51
  • 63