【正文开始】
注意:本篇所讲方法过于辣鸡,新方法见:QmlControls/FramelessWindow at master · mengps/QmlControls · GitHub
这段话是后来加的。。
使用 Qt 制作的无边框窗口,只需在其 flag 中加入 FramelessWindowHint。
然而,无边框窗口意味着,无法使用原有的边框拉伸,拖拽功能。
在 QWidget 中,有很多实现的方法,比如重写
+ mouseMoveEvent(QMouseEvent *event)
+ mousePressEvent(QMouseEvent *event)
+ mouseReleaseEvent(QMouseEvent *event)
这几个事件即可很容易的完成无边框窗口的拉伸,拖拽功能。ps :重写 nativeEvent(const QByteArray &eventType, void *message, long *result) 可以获得最好的效果~
但是在 Qml 中,由于 QWindow 和 QWidget 的实现方式完全不同,而 QQuickwindow 继承自 QWindow,使用上述的方法当然也可以如 widget 一样的工作,然鹅经过测试闪烁严重,体验极差,于是就有了另一种方法。
直接使用 MouseArea 进行拉伸,拖拽。
qml 代码如下:
import QtQuick 2.7
/*
↑ ↑ ↑
←|1| |2| |3|→
←|4| |5| |6|→
←|7| |8| |9|→
↓ ↓ ↓
分8个缩放区域
|5|为拖动区域
target 缩放目标
startPoint 鼠标起始点
fixedPont 用于固定窗口的点
每一个area 大小 8 x 8
*/
Item
{
id: area
property var target: undefined;
property point startPoint: Qt.point(0, 0);
property point fixedPont: Qt.point(0, 0);
MouseArea
{
id: area1
x: 0
y: 0
width: 8
height: 8
hoverEnabled: true
onEntered: cursorShape = Qt.SizeFDiagCursor;
onExited: cursorShape = Qt.ArrowCursor;
onPressed: startPoint = Qt.point(mouseX, mouseY);
onPositionChanged:
{
if(pressed)
{
var offsetX = mouse.x - startPoint.x;
var offsetY = mouse.y - startPoint.y;
if ((target.width - offsetX) >= target.minimumWidth) //如果本次调整小于最小限制,则调整为最小
{
target.width -= offsetX;
target.x += offsetX;
}
else
{
target.x += (target.width - target.minimumWidth);
target.width -= (target.width - target.minimumWidth);
}
if ((target.height - offsetY) >= target.minimumHeight && offsetY != 0)
{
target.height -= offsetY;
target.y += offsetY;
}
}
}
}
MouseArea
{
id: area2
x: 8
y: 0
width: target.width - 16
height: 8
hoverEnabled: true
onEntered: cursorShape = Qt.SizeVerCursor;
onExited: cursorShape = Qt.ArrowCursor;
onPressed: startPoint = Qt.point(mouseX, mouseY);
onPositionChanged:
{
if(pressed)
{
var offsetY = mouse.y - startPoint.y;
if ((target.height - offsetY) >= target.minimumHeight && offsetY != 0)
{
target.height -= offsetY;
target.y += offsetY;
}
}
}
}
MouseArea
{
id: area3
x: target.width - 8
y: 0
width: 8
height: 8
hoverEnabled: true
onEntered: cursorShape = Qt.SizeBDiagCursor;
onExited: cursorShape = Qt.ArrowCursor
onPressed:
{
startPoint = Qt.point(mouseX, mouseY);
fixedPont = Qt.point(target.x, target.y)
}
onPositionChanged:
{
if(pressed)
{
var offsetX = mouse.x - startPoint.x;
var offsetY = mouse.y - startPoint.y;
print (offsetX, offsetY)
if ((target.width + offsetX) >= target.minimumWidth && offsetX != 0)
{
target.width += offsetX;
target.x = fixedPont.x;
}
if ((target.height - offsetY) >= target.minimumHeight && offsetY != 0)
{
target.height -= offsetY;
target.y += offsetY;
}
}
}
}
MouseArea
{
id: area4
x: 0
y: 8
width: 8
height: target.height - 16
hoverEnabled: true
onEntered: cursorShape = Qt.SizeHorCursor;
onExited: cursorShape = Qt.ArrowCursor;
onPressed:
{
startPoint = Qt.point(mouseX, mouseY);
}
onPositionChanged:
{
if(pressed)
{
var offsetX = mouse.x - startPoint.x;
if ((target.width - offsetX) >= target.minimumWidth)
{
target.width -= offsetX;
target.x += offsetX;
}
}
}
}
MoveMouseArea
{
id: area5
x: 8
y: 8
width: area.target.width - 16
height: area.target.height - 16
target: area.target
}
MouseArea
{
id: area6
x: target.width - 8
y: 8
width: 8
height: target.height - 16
hoverEnabled: true
property real fixedX: 0;
onEntered: cursorShape = Qt.SizeHorCursor;
onExited: cursorShape = Qt.ArrowCursor;
onPressed:
{
startPoint = Qt.point(mouseX, mouseY);
fixedPont = Qt.point(target.x, target.y)
}
onPositionChanged:
{
if(pressed)
{
var offsetX = mouse.x - startPoint.x;
if ((target.width + offsetX) >= target.minimumWidth && offsetX != 0)
{
target.width += offsetX;
target.x = fixedPont.x;
}
}
}
}
MouseArea
{
id: area7
x: 0
y: target.height - 8
width: 8
height: target.height - 16
hoverEnabled: true
property real fixedX: 0;
onEntered: cursorShape = Qt.SizeBDiagCursor;
onExited: cursorShape = Qt.ArrowCursor;
onPressed:
{
startPoint = Qt.point(mouseX, mouseY);
fixedPont = Qt.point(target.x, target.y)
}
onPositionChanged:
{
if (pressed)
{
var offsetX = mouse.x - startPoint.x;
var offsetY = mouse.y - startPoint.y;
if ((target.width - offsetX) >= target.minimumWidth && offsetX != 0)
{
target.width -= offsetX;
target.x += offsetX;
}
if ((target.height + offsetY) >= target.minimumHeight && offsetY != 0)
{
target.height += offsetY;
target.y = fixedPont.y;
}
}
}
}
MouseArea
{
id: area8
x: 8
y: target.height - 8
width: target.height - 16
height: 8
hoverEnabled: true
property real fixedX: 0;
onEntered: cursorShape = Qt.SizeVerCursor;
onExited: cursorShape = Qt.ArrowCursor;
onPressed:
{
startPoint = Qt.point(mouseX, mouseY);
fixedPont = Qt.point(target.x, target.y)
}
onPositionChanged:
{
if (pressed)
{
var offsetY = mouse.y - startPoint.y;
if ((target.height + offsetY) >= target.minimumHeight && offsetY != 0)
{
target.height += offsetY;
target.y = fixedPont.y;
}
}
}
}
MouseArea
{
id: area9
x: target.width - 8
y: target.height - 8
width: 8
height: 8
hoverEnabled: true
onEntered: cursorShape = Qt.SizeFDiagCursor;
onExited: cursorShape = Qt.ArrowCursor
onPressed:
{
startPoint = Qt.point(mouseX, mouseY);
fixedPont = Qt.point(target.x, target.y)
}
onPositionChanged:
{
if(pressed)
{
var offsetX = mouse.x - startPoint.x;
var offsetY = mouse.y - startPoint.y;
if ((target.width + offsetX) >= target.minimumWidth && offsetX != 0)
{
target.width += offsetX;
target.x = fixedPont.x;
}
if ((target.height + offsetY) >= target.minimumHeight && offsetY != 0)
{
target.height += offsetY;
target.y = fixedPont.y;
}
}
}
}
}
还有很多判断 minimum,maximum 什么的没有写全,但很简单,就不多展示了。
其中的 MoveMouseArea 为:
import QtQuick 2.7
MouseArea
{
hoverEnabled: true
property var target: undefined;
property point startPoint: Qt.point(0, 0);
property point offsetPoint: Qt.point(0, 0);
onPressed:
{
cursorShape = Qt.SizeAllCursor;
startPoint = Qt.point(mouseX, mouseY);
}
onPositionChanged:
{
if(pressed)
{
offsetPoint = Qt.point(mouse.x - startPoint.x, mouse.y - startPoint.y);
target.x = target.x + offsetPoint.x;
target.y = target.y + offsetPoint.y;
}
}
onReleased:
{
cursorShape = Qt.ArrowCursor;
}
}
【结语】
因为在其他地方并不需要拉伸操作,所以将区域 |5| 单独作为一个 qml 文件使用。
还有一点关于 qml,闪烁严重的一部分原因是使用了 anchors 定位引起的,所以在窗口中的最底层的 item 使用坐标方式进行定位。其他 item 则不用。
可以测试一下,还算可以,基本可以使用了,但仍然达不到 widget 那么流畅完美的程度。