Evgenij LegotskojSept. 14, 2017, 2:05 a.m.

QML - Tutorial 031. Disable the system window framing in QML and write the code for processing the move and resize windows

If for some reason, you decide to abandon the standard system window frame and implement all the Title Bar windows on your own in QML, then you can easily implement this with QML, which is even easier than in C ++, in my opinion. For acquaintance you can look at the article on customization of the application window in the AIMP style . There is a significant amount of code for implementing the mechanics of moving the window, as well as its resize. The advantage of QML in this case is that QML immediately provides the layout of the application, so you can use MouseArea and anchors to immediately determine the desired processing when clicking and moving the mouse without any special calculation of the cursor position in the window area.

And the mechanics of calculating the change in size and position will be similar to the one used in the article on customizing the application in C ++. That is, it will be necessary to remember the position where the mouse button was pressed, and then, relative to this position, make a resize and move the application window until the button is released.

Content

As you can see in the figure above, you will need to create 5 MouseArea regions, four of which will be responsible for application resizing, and the fifth central for the application migration. That is, you can move the application by holding the mouse button anywhere in the fifth central area.

If you need a special Title Bar, then it can also be responsible for moving the application window. That is, it is not necessary to make the entire central region sensitive to movement.

main.qml

The application is created by default and only the main.qml file will be changed, which I will give as an example.

import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3

ApplicationWindow {
    id: mainWindow
    visible: true
    width: 640
    height: 480

    flags: Qt.FramelessWindowHint // Disable window frame

    // Declare properties that will store the position of the mouse cursor
    property int previousX
    property int previousY

    MouseArea {
        id: topArea
        height: 5
        anchors {
            top: parent.top
            left: parent.left
            right: parent.right
        }
        // We set the shape of the cursor so that it is clear that this resizing
        cursorShape: Qt.SizeVerCursor

        onPressed: {
            // We memorize the position along the Y axis
            previousY = mouseY
        }

        // When changing a position, we recalculate the position of the window, and its height
        onMouseYChanged: {
            var dy = mouseY - previousY
            mainWindow.setY(mainWindow.y + dy)
            mainWindow.setHeight(mainWindow.height - dy)
        }
    }

    // Similar calculations for the remaining three areas of resize
    MouseArea {
        id: bottomArea
        height: 5
        anchors {
            bottom: parent.bottom
            left: parent.left
            right: parent.right
        }
        cursorShape: Qt.SizeVerCursor

        onPressed: {
            previousY = mouseY
        }

        onMouseYChanged: {
            var dy = mouseY - previousY
            mainWindow.setHeight(mainWindow.height + dy)
        }
    }

    MouseArea {
        id: leftArea
        width: 5
        anchors {
            top: topArea.bottom
            bottom: bottomArea.top
            left: parent.left
        }
        cursorShape: Qt.SizeHorCursor

        onPressed: {
            previousX = mouseX
        }

        onMouseXChanged: {
            var dx = mouseX - previousX
            mainWindow.setX(mainWindow.x + dx)
            mainWindow.setWidth(mainWindow.width - dx)
        }
    }

    MouseArea {
        id: rightArea
        width: 5
        anchors {
            top: topArea.bottom
            bottom: bottomArea.top
            right: parent.right
        }
        cursorShape:  Qt.SizeHorCursor

        onPressed: {
            previousX = mouseX
        }

        onMouseXChanged: {
            var dx = mouseX - previousX
            mainWindow.setWidth(mainWindow.width + dx)
        }
    }

    // The central area for moving the application window
    // Here you already need to use the position both along the X axis and the Y axis
    MouseArea {
        anchors {
            top: topArea.bottom
            bottom: bottomArea.top
            left: leftArea.right
            right: rightArea.left
        }

        onPressed: {
            previousX = mouseX
            previousY = mouseY
        }

        onMouseXChanged: {
            var dx = mouseX - previousX
            mainWindow.setX(mainWindow.x + dx)
        }

        onMouseYChanged: {
            var dy = mouseY - previousY
            mainWindow.setY(mainWindow.y + dy)
        }
    }
}
We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.
Support the author Donate
M

Огромное спасибо

Драсте, спасибо за хороший урок.

Однако, остались вопросы:

При использовании флага "Qt.FramelessWindowHint", приложение исправно работает, но пропадает с панели задач и из приложений в диспетчере. Вследствие этого приложение, если его свернуть, становится неюзабельным, и с ним ничего нельзя сделать, кроме как закрыть через процессы в диспетчере.

Не подскажите, как это исправить, из-за чего это могло произойти, или, хотя бы, в какую сторону копать?

Дальше идёт код, что бы показать проблему:
import QtQuick 2.6
import QtQuick.Window 2.2

Window {
    visible: true
    width: 640
    height: 480
    flags: Qt.FramelessWindowHint
    title: qsTr("Hello World")

    TextEdit {
        id: textEdit
        text: qsTr("Enter some text...")
        verticalAlignment: Text.AlignVCenter
        anchors.top: parent.top
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.topMargin: 20
        }
    }
}

Это скорее всего баг Qt под конкретной операционной системой. Какую используете?
Дело в том, что я проверил Ваш код под свой рабочей системой (KDE Neon 5.8) и всё работает стабильно, без нареканий. То есть минимизация окна происходит без проблем. Под Windows проверить не могу, на данный момент у меня нет рабочих установок этой системы.

Использую Windows 7 Ultimate.

Причём, если использовать этот флаг при QT Widgets, а не QML, то всё работает правильно.

Тогда это однознано баг, я бы глянул на официальном багтрекере Qt, есть ли информация об этом баге, и возможно стоит создать таск с этим багом.

Спасибо! Этим и займусь. Ещё попробую скинуть проект другу, посмотрю, как QT будет справляться там.

M

После отключения системного обрамления не работают minimumHeight и minimumWidth. Что делать?


Задать свои property в окне и проверять их в методах изменения размера для topArea, bottomArea, rightArea, leftArea.

В обработчиках onMouseYChanged, onMouseXChanged.
Из-за отключения обрамления не отслеживаются минимальные рамеры, поэтому нужно следить за этим самостоятельно
M

Еще не могли бы подсказать как сделать чтобы отображалась иконка, так как она тоже исчезла. Весь интернет обыскал так и не нашел решения.

Какая иконка? Которая была в оформлении окна? Ну всё логично, оформление отключили - иконка исчезла. Хотите иконку, придётся самосттоятельно добавить её в левый верхний угол окна через какой-нибудь QML тип Image.

Вы про какую вообще иконку говорите?
M

Извиняюсь за не точность. Я имел в виду  иконку в Taskbar.


Вы же под Windows пишете? Есть такой класс QWinTaskbarButton, у него есть property overlayIcon . Возможно, стоит поработать с этим клсассом и установить туда иконку. Вот в этой статье есть пример работы с этим QWinTaskbarButton .


M

Огромное спасибо, работает.

Я бы вместо совытий mouseXChanged  и mouseYChanged использовал positionChanged, так как у двух первых есть один недостаток, они производные от mouseX и Y которые содержат текущие координаты X и Y соответсвенно - это значит что они обновляются (записываются) регулярно при нажатой кнопки мыши (если свойство hoverEnabled будет true то они будут обновляться и без нажатия кнопок мыши). Это значит, что  эти свойства вызывают ложную логику, если вы еще не двигали курсор мыши, а просто нажали кнопку мыши. В то время как positionChanged срабатывает только когда положение курсора в действительности было изменено при нажатой кнопки мыши (если hoverEnabled = false, опять же).


Например, в случае с обработчиками событий onMouseXChanged  и onMouseYChanged окно бы ложно сворачивалось при простом нажатии кнопки мыши (так как эти свойства записываются постоянно при нажатой кнопке). PositionChanged дает пользователю время на обдумывание, нужно ли ему свернуть окно и начать перемещение или нет. Он может отменить это действие просто отпустив кнопку мыши не двигая курусор, как это реализованно с окнами windows. Да и код выглядит, согласитесь,  поменьше.
MouseArea {
	id: appMovigArea

	anchors.fill: windowTitleBar
	hoverEnabled: false
	onPressed: {
		previousMouseXPosition = mouseX;
		previousMouseYPosition = mouseY;
	}

	onPositionChanged: {
		if(window.visibility == Window.Maximized) {
			showNormal();
		} else {
			window.setX(window.x + (mouseX - previousMouseXPosition));
			window.setY(window.y + (mouseY - previousMouseYPosition));
		}
	}
}


m

Здравствуйте. Сделал подобным образом ресайз и в Qt Widgets, и в QML. Везде получаю, что при изменении размера через левую или верхннюю границы проихсодит мерцание подобно как на этом видео . Всё перелопатил, нигде ответа не нашел. Не знаете как это победить?

Добрый день. Нет, если сами по себе координаты при ресайзе все подсчитываются правильно, то это уже проблема графической подсистемы в ОС и работы с X11, если вы конечно под Linux собирали проект. В том видео в исходниках крутят платформозависимые флаги. На тему тех флагов есть Bug на багтрекере Qt . Возможно также локальная проблема с конкретным дистрибутивом, если на мейнстримовых дистрибутивах всё работает хорошо. В общем скорее всего это та помойка, в которой не хотелось бы копаться.

Comments

Only authorized users can post comments.
Please, Log in or Sign up
Card image cap
Pulsum Via

Project for travelers from EVILEG.

Go
Fornex

Let me recommend you a great European Fornex hosting.

Fornex has proven itself to be a stable host over the years.

For Django projects I recommend VPS hosting

Following the link you will receive a 5% discount on shared hosting services, dedicated servers, VPS and VPN

View Hosting
Share on social networks
Donate

The EVILEG project has switched to a non-commercial basis and will develop solely on the enthusiasm of the site creator, the enthusiasm of users, donations and the hosting referral system

Thank you for your support

Available ways to support the project

PayPal

PatreonYandex.MoneyMore
M

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:20points,
  • Rating points-10
k

C++ - Test 005. Structures and Classes

  • Result:83points,
  • Rating points4
k

C++ - Test 002. Constants

  • Result:58points,
  • Rating points-2
Last comments
Ds

Android and QML - Adding Splash Screen

Интересен формат иконки, если это png, то как решается проблема scalability? не растягивается ли лого на китайфонах с 1280х2500? У меня просто сплеш скрин с градиентом и логотипом, и вот несколь…
p

Qt/C++ - Lesson 023. Moving QGraphicsItem on QGraphicsScene with mouse help

FIGURE Abdominopelvic regions. Zjuaqd https://newfasttadalafil.com/ - Cialis Cialis Recommendations for preparing children and adolescents for invasive cardiac procedures a statement…
KG

How to use nested forms in Django

Спасибо за полезную статью. Подскажите пожалуйста, что делать если нужно реализовать большее количество вложенных форм? Например если на модель Address ссылается fk другой модели, на котору…

Qt/C++ - Lesson 051. QMediaPlayer – simple audio player

Не думаю, QMediaPlayer в один поток проигрывает. Если вам нужно одновременное воспроизведение нескольких аудиоисточников, то вам нужна Bass audio library , насколько знаю, её обычно и…
AG

Qt/C++ - Lesson 051. QMediaPlayer – simple audio player

есть такая вообще возможность ?
Now discuss on the forum
AB

Sorting the added QML elements in the ListModel

I am writing an alarm clock in QML, I am required to sort the alarms in ascending order (depending on the date or time (if there are several alarms on the same day). I've done the sorting …

Изменение поведения QGroupBox при клике на его чекбокс

Я вынес виджеты вынес за пределы QGroupBox в итоге.

QSqlRelatipnalTabelModel Qt 4.8.1 как получить id внешней связи?

Есть еще принципиально другой вариант решить раз и навсегда вопрос с полей id внешней связи. Это форкнуть Qt 4.8.1 QSqlTableModel, то есть создать свою ветку развития. Например создадим кл…

Добавление AndroidManifest.xml в cmake

Добрый день. Как добавить AndroidManifest.xml в cmake? Это не работвет set(ANDROID_PACKAGE_SOURCE_DIR ${PROJECT_SOURCE_DIR}/android CACHE INTERNAL "")set(ANDROID_BUID_DIR ${CMAKE_C…
s

Событие wheelEvent для виджета QLineEdit

вот что получилось: gui.py from PyQt5 import QtCore, QtGui, QtWidgets class LineEdit(QtWidgets.QLineEdit): def wheelEvent(self, event): #print("_") delta = 1 if e…
About
Services
© EVILEG 2015-2022
Recommend hosting TIMEWEB