Diego
Diego

Reputation: 357

QML: Move a frameless window by dragging

I have a frameless QQuickWindow, and I want to move it with the mouse by dragging. Before trying in my big application, I have created a simple test application to try what I found here, using cursor position from C++ class to avoid problems from QML: http://www.tickanswer.com/solved/5390888353/dragging-frameless-window-jiggles-in-qml

But I failed with the code below. When I press over the red RECT and move the mouse, my yellow rect (root RECT) moves, but only inside the original size it had (in this case, 500x500)... What am I doing wrong?

Thanks in advance

In my main.cpp:

int main(int argc, char *argv[])
{   
    QtQuickControlsApplication a(argc, argv);

    QQuickView* pView = new QQuickView();

    CursorPosProvider mousePosProvider;
    pView->rootContext()->setContextProperty("mousePosition", &mousePosProvider);
    pView->setSource(QUrl("qrc:/Test.qml"));
    pView->setFlags(Qt::FramelessWindowHint);
    pView->show();

    return a.exec();
}

Test.qml:

import QtQuick 2.0

Rectangle {
    id: myWindow
    width: 500; height: 500
    color: "yellow"

    Rectangle {
        anchors.centerIn: parent
        width: 200; height: 200

        color: "red"

        MouseArea {
            id: titleBarMouseRegion
            property var clickPos
            anchors.fill: parent

            onPressed:  clickPos = { x: mousePosition.cursorPos().x, y: mousePosition.cursorPos().y }

            onPositionChanged: {
                myWindow.x = mousePosition.cursorPos().x - clickPos.x
                myWindow.y = mousePosition.cursorPos().y - clickPos.y
            }
        }
    }
}

cursorprovider.h:

#ifndef CURSORPOSPROVIDER_H
#define CURSORPOSPROVIDER_H

#include <QObject>
#include <QPointF>
#include <QCursor>

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

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

#endif // CURSORPOSPROVIDER_H

Upvotes: 2

Views: 2217

Answers (2)

Diego
Diego

Reputation: 357

I have changed the structure, I have used a QQuickWidget with a QML inside, and now I have what I wanted. Here is my code in case anyone needs something similar

main.cpp

...
MovableWidget *view = new MovableWidget;
view->setSource(QUrl("qrc:/Test.qml"));
view->setWindowFlags(Qt::FramelessWindowHint);
view->show();
...

Test.qml

import QtQuick 2.0

Rectangle {
    id: myWindow
    width: 500; height: 500
    color: "yellow"

    Rectangle {
        anchors.centerIn: parent
        width: 200; height: 200

        color: "red"
    }
}

MovableWidget.cpp

#include "movableWidget.h"

#include <QMouseEvent>

// ****************************************************************************
MovableWidget::MovableWidget(QWidget *parent)
    : QQuickWidget(parent),
    m_previousPos(0,0)
{
    installEventFilter(this);
}

// ****************************************************************************
bool MovableWidget::eventFilter(QObject *obj, QEvent *event)
{
    if (event->type() == QEvent::MouseButtonPress)
    {
         m_previousPos = QCursor:os();
    }
    else if (event->type() == QEvent::MouseMove)
    {
         QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);

         if(mouseEvent->buttons() == Qt::LeftButton)
         {
             QPoint offset = m_previousPos - QCursor:os();
             m_previousPos = QCursor:os();
             move(pos() - offset);
        }
    }

    return false;
}

Upvotes: 0

lolo
lolo

Reputation: 704

I wrote this example and I see no jiggle (running on Linux)

ApplicationWindow {
    id: iWindow
    visible: true
    title: "My title"
    color: "gray"
    width: 500
    height: 500

    MouseArea{
        id: iMouseArea
        property int prevX: 0
        property int prevY: 0
        anchors.fill: parent
        onPressed: {prevX=mouse.x; prevY=mouse.y}
        onPositionChanged:{
            var deltaX = mouse.x - prevX;
            iWindow.x += deltaX;
            prevX = mouse.x - deltaX;

            var deltaY = mouse.y - prevY
            iWindow.y += deltaY;
            prevY = mouse.y - deltaY;
        }
    }

}

Upvotes: 4

Related Questions