如何返回无框窗口中边框的调整大小逻辑?
QML 中的代码:
import QtQuick
import QtQuick.Controls 2.5
import Qt5Compat.GraphicalEffects
import NR 1.0
Window {
id: mainWindow
width: 640
height: 720
visible: true
title: qsTr("Hello World")
flags: Qt.Window | Qt.FramelessWindowHint
color: "transparent"
// (1)
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)
}
}
// Some code of another Items here
}
我在左侧尝试了此代码:
MouseArea {
id: leftSideMouseArea
anchors.fill: parent
property point lastMousePos: Qt.point(0, 0)
onPressed: { lastMousePos = Qt.point(mouseX, mouseY); }
onMouseXChanged: mainWindow.width += (mouseX + lastMousePos.x)
}
我将此代码放在 (1) 位置,但它不起作用 - 单击(不移动)窗口会调整到右侧大小,并且应用程序崩溃并出现错误:
QQuickPaintedItem::textureProvider:只能在 暴露窗口的渲染线程
你能帮我吗?
谢谢!
从
Qt5.15
开始,我们有了startSystemResize,它执行本机调整大小,建议不要使用将单击位置与当前位置进行比较之类的方法。
功能非常简单;一旦经过边缘,窗口就会开始调整大小。
无框窗户的示例如下所示:
使用此属性更改可按下鼠标的窗口边缘的偏移量。
property
int
edgeOffest
:5
也可用于移动窗口,您可以使用
DragHandler
,它在激活时会调用 startSystemMove。
Window {
width: 200; height: 100
color: '#fab'
flags: Qt.Window | Qt.FramelessWindowHint
DragHandler {
onActiveChanged: if(active) startSystemMove();
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.LeftButton
property int edges: 0;
property int edgeOffest: 5;
function setEdges(x, y) {
edges = 0;
if(x < edgeOffest) edges |= Qt.LeftEdge;
if(x > (width - edgeOffest)) edges |= Qt.RightEdge;
if(y < edgeOffest) edges |= Qt.TopEdge;
if(y > (height - edgeOffest)) edges |= Qt.BottomEdge;
}
cursorShape: {
return !containsMouse ? Qt.ArrowCursor:
edges == 3 || edges == 12 ? Qt.SizeFDiagCursor :
edges == 5 || edges == 10 ? Qt.SizeBDiagCursor :
edges & 9 ? Qt.SizeVerCursor :
edges & 6 ? Qt.SizeHorCursor : Qt.ArrowCursor;
}
onPositionChanged: setEdges(mouseX, mouseY);
onPressed: {
setEdges(mouseX, mouseY);
if(edges && containsMouse) {
startSystemResize(edges);
}
}
}
}
不过,我不建议开发具有自定义功能的自定义窗口,这会迫使您处理大量功能,同时仍然感觉不像原生功能。
但是,有一些 github 项目为此提供了一些辅助库,所以请看一下这些项目。
我想不出更好的方法来做到这一点
这是一个工作示例:
import QtQuick 2.15
import QtQuick.Window 2.15
Window {
id: window
width: 640
height: 480
visible: true
title: qsTr("Hello World")
flags: Qt.Window | Qt.FramelessWindowHint
Rectangle
{
id: dragItemRight
anchors.top: parent.top
anchors.bottom: parent.bottom
width: 5
color: "red"
x: window.width - width
onXChanged:
{
if (dragItemRightMouse.drag.active)
{
window.width = dragItemRight.x + width
}
}
MouseArea
{
id: dragItemRightMouse
anchors.fill: parent
drag.target: parent
drag.axis: Drag.XAxis
cursorShape: Qt.SizeHorCursor
drag.minimumX: 300
drag.onActiveChanged:
{
if (!drag.active)
{
dragItemRight.x = Qt.binding(function() { return window.width - width })
}
}
}
}
Rectangle
{
id: dragItemBottom
anchors.left: parent.left
anchors.right: parent.right
height: 5
color: "red"
y: window.height - height
onYChanged:
{
if (dragItemBottomMouse.drag.active)
{
window.height = dragItemBottom.y + height
}
}
MouseArea
{
id: dragItemBottomMouse
anchors.fill: parent
drag.target: parent
drag.axis: Drag.YAxis
cursorShape: Qt.SizeVerCursor
drag.minimumY: 300
drag.onActiveChanged:
{
if (!drag.active)
{
dragItemBottom.y = Qt.binding(function() { return window.height - height })
}
}
}
}
Rectangle
{
id: dragItemBottomRight
width: 5
height: 5
color: "green"
x: window.width - width
y: window.height - height
onYChanged:
{
if (dragItemBottomRightMouse.drag.active)
{
window.height = dragItemBottomRight.y + height
}
}
onXChanged:
{
if (dragItemBottomRightMouse.drag.active)
{
window.width = dragItemBottomRight.x + width
}
}
MouseArea
{
id: dragItemBottomRightMouse
anchors.fill: parent
drag.target: parent
drag.axis: Drag.XAndYAxis
drag.minimumX: 300
drag.minimumY: 300
cursorShape: Qt.SizeFDiagCursor
drag.onActiveChanged:
{
if (!drag.active)
{
dragItemBottomRight.x = Qt.binding(function() { return window.width - width })
dragItemBottomRight.y = Qt.binding(function() { return window.height - height })
}
}
}
}
}
我找到了解决方案:
import QtQuick
import QtQuick.Controls 2.15
import Qt5Compat.GraphicalEffects
import NR 1.0
Window {
id: mainWindow
width: 640
height: 720
visible: true
title: qsTr("Hello World")
flags: Qt.Window | Qt.FramelessWindowHint
color: "transparent"
property point startMousePos
property point startWindowPos
property size startWindowSize
function absoluteMousePos(mouseArea) {
var windowAbs = mouseArea.mapToItem(null, mouseArea.mouseX, mouseArea.mouseY)
return Qt.point(windowAbs.x + mainWindow.x,
windowAbs.y + mainWindow.y)
}
MouseArea {
id: moveArea
anchors.fill: title
property point mPos;
onPressed: {
mPos = Qt.point(mouseX, mouseY)
}
onPositionChanged: {
mainWindow.setX(mainWindow.x + mouseX - mPos.x)
mainWindow.setY(mainWindow.y + mouseY - mPos.y)
}
}
MouseArea {
id: leftArea
anchors.top: parent.top
anchors.topMargin: 48
anchors.bottom: parent.bottom
anchors.bottomMargin: 5
cursorShape: Qt.SizeHorCursor
width: 5
onPressed: {
startMousePos = absoluteMousePos(leftArea)
startWindowPos = Qt.point(mainWindow.x, mainWindow.y)
startWindowSize = Qt.size(mainWindow.width, mainWindow.height)
}
onMouseXChanged: {
var abs = absoluteMousePos(leftArea)
var newWidth = Math.max(mainWindow.minimumWidth, startWindowSize.width - (abs.x - startMousePos.x))
var newX = startWindowPos.x - (newWidth - startWindowSize.width)
mainWindow.x = newX
mainWindow.width = newWidth
}
Rectangle {
anchors.fill: parent
color: "red"
}
}
MouseArea {
id: rightArea
width: 5
x: parent.width - rightArea.width
anchors.right: parent.rigth
anchors.top: parent.top
anchors.rightMargin: 5
anchors.topMargin: 48
anchors.bottom: parent.bottom
anchors.bottomMargin: 5
cursorShape: Qt.SizeHorCursor
onPressed: {
startMousePos = absoluteMousePos(rightArea)
startWindowPos = Qt.point(mainWindow.x, mainWindow.y)
startWindowSize = Qt.size(mainWindow.width, mainWindow.height)
}
onMouseXChanged: {
var abs = absoluteMousePos(rightArea)
var newWidth = Math.max(mainWindow.minimumWidth, startWindowSize.width + (abs.x - startMousePos.x))
mainWindow.width = newWidth
}
Rectangle {
anchors.fill: parent
color: "red"
}
}
MouseArea {
id: buttonArea
y: parent.height - buttonArea.height
height: 5
anchors.leftMargin: 5
anchors.left: parent.left
anchors.rightMargin: 5
anchors.right: parent.right
anchors.bottom: parent.bottom
cursorShape: Qt.SizeVerCursor
onPressed: {
startMousePos = absoluteMousePos(buttonArea)
startWindowPos = Qt.point(mainWindow.x, mainWindow.y)
startWindowSize = Qt.size(mainWindow.width, mainWindow.height)
}
onMouseYChanged: {
var abs = absoluteMousePos(buttonArea)
var newHeight = Math.max(mainWindow.minimumHeight, startWindowSize.height + (abs.y - startMousePos.y))
mainWindow.height = newHeight
}
Rectangle {
anchors.fill: parent
color: "red"
}
}
}
我有这个问题的解决方案。
https://github.com/tongmon/qt-frameless-windows
如果你分析我的模板项目,你可以知道在无框Qt窗口上启用调整大小功能的关键点是WM_NCHITTEST消息。
像下面的代码一样。
case WM_NCHITTEST: {
RECT winrect;
GetWindowRect(msg->hwnd, &winrect);
long x = GET_X_LPARAM(msg->lParam);
long y = GET_Y_LPARAM(msg->lParam);
if (x >= winrect.left && x < winrect.left + m_resize_border_width &&
y < winrect.bottom && y >= winrect.bottom - m_resize_border_width)
{
*result = HTBOTTOMLEFT;
return true;
}
if (x < winrect.right && x >= winrect.right - m_resize_border_width &&
y < winrect.bottom && y >= winrect.bottom - m_resize_border_width)
{
*result = HTBOTTOMRIGHT;
return true;
}
if (x >= winrect.left && x < winrect.left + m_resize_border_width &&
y >= winrect.top && y < winrect.top + m_resize_border_width)
{
*result = HTTOPLEFT;
return true;
}
if (x < winrect.right && x >= winrect.right - m_resize_border_width &&
y >= winrect.top && y < winrect.top + m_resize_border_width)
{
*result = HTTOPRIGHT;
return true;
}
if (x >= winrect.left && x < winrect.left + m_resize_border_width)
{
*result = HTLEFT;
return true;
}
if (x < winrect.right && x >= winrect.right - m_resize_border_width)
{
*result = HTRIGHT;
return true;
}
if (y < winrect.bottom && y >= winrect.bottom - m_resize_border_width)
{
*result = HTBOTTOM;
return true;
}
if (y >= winrect.top && y < winrect.top + m_resize_border_width)
{
*result = HTTOP;
return true;
}
*result = HTTRANSPARENT;
break;
}