qml中无框拖window"jiggles"
Dragging frameless window "jiggles" in qml
我有一个无框架的 ApplicationWindow,我想使用 this 问题的答案使其可拖动。然而,正如有人在评论中所说,当我快速移动 window 时,它会摇晃很多。
我一直在努力改进它,但没有成功。
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("WIP")
id: mainWindow
flags: Qt.SubWindow | Qt.Tool | Qt.FramelessWindowHint | Qt.WindowSystemMenuHint
header: ToolBar{
MouseArea{
anchors.fill: parent
onDoubleClicked: mainWindow.visibility!="2"?mainWindow.showNormal():mainWindow.showMaximized()
id: maMainWindow
property variant clickPos: "0,0"
onPressed: {
clickPos = Qt.point(mouse.x,mouse.y)
}
onPositionChanged: {
var delta = Qt.point(mouse.x-clickPos.x, mouse.y-clickPos.y)
mainWindow.x += delta.x;
mainWindow.y += delta.y;
}
}
}
}
如果我添加制表符和一些元素,情况会变得更糟。
C++ 能否以某种方式提高其性能?
我认为您无能为力,这只是使用绑定构建 GUI 的副作用,并且绑定评估与渲染不同步。结果,当您移动或调整 window 的大小时,所有内容都像弹性一样摆动,直到值 "catches up"。这是 QML 的事情,在小部件中你不会得到那种行为,因为 UI 不是围绕绑定构建的。基本上,每个绑定链的评估都有延迟,当 GUI 被绘制时,它捕获并显示绑定链传播的延迟,链中的第一个对象已经在它们的新位置,而那些更靠后的位置可能会在传播过程中落后几个步骤。当然,您的 window 是否有框架与该问题完全无关。
克服这个问题需要控制绑定处理信号的方式,我认为目前还没有这样的事情。基本上,诀窍是以某种方式强制绘图等待,直到链中的每个绑定都被评估,并在启动另一系列评估之前在两者之间绘制。
自然地,您拥有的元素越多,每次更改级联所有元素所需的时间就越长,从而使效果更加明显。它还取决于您的系统有多快 - 因为这决定了评估绑定链的延迟,例如我的系统很快并且您的示例代码不会产生抖动。然而,虽然在调整大小时发生这种情况是可以理解的,但它回避了为什么当您只是移动 window 时会发生这种情况的问题。毕竟,这不应该真正改变 window 中 UI 元素的相对位置。我怀疑发生这种情况是因为在内部这些对象是在 "absolute screen space" 中绘制的,因此当您移动 window 时,这会导致每个元素的实际绝对位置发生变化,即使它们相对于window,导致此行为。不理想...不仅引入了不良的视觉行为,而且引入了许多额外的评估,这些评估似乎是不必要的开销。
请注意,这些只是我模糊的怀疑,我还没有详细调查此事,希望有人能提供一种快速简便的方法来处理这个问题。现在我忽略了这个问题,希望它不会太烦人,考虑到我专注于与 window 的位置和几何形状的连续变化无关的软件;)顺便说一句,即使我第一次看到这在 QML 中,最近几年我在其他 "modern gui" 框架中也注意到了它。这是可以理解的,因为这样的框架为了快速原型制作而转向性能较慢的语言,并结合 "fluid" 异步非阻塞渲染。
我遇到了同样的问题,性能还可以,但是在 linux 上它在屏幕上跳来跳去 "jiggling"。我已经通过在 C++ 中编写一个助手 class 来解决它,我将其公开为 QML 上下文 属性。这个解决方案对我帮助很大。我有非常复杂的 UI,它工作得很好,性能非常好。
让我们开始吧。
1) 你需要一个帮手 class 像这样:
class CursorPosProvider : public QObject
{
Q_OBJECT
public:
explicit CursorPosProvider(QObject *parent = nullptr) : QObject(parent)
{
}
virtual ~CursorPosProvider() = default;
Q_INVOKABLE QPointF cursorPos()
{
return QCursor::pos();
}
};
这是一个非常简单的 class,它只是从 C++ 端为您提供光标位置,这很奇怪,但是当您在 QML 中执行相同操作时,您会遇到问题(至少在 linux 上) .
2) 将其作为上下文 属性 公开给 QML 引擎,我已经通过以下方式完成了:
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQuickView view;
CursorPosProvider mousePosProvider;
view.rootContext()->setContextProperty("mousePosition", &mousePosProvider);
view.setSource(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
3) 好的,现在我们准备好开始 QML 部分了。
我有一个 Qt Quick 组件,它实现了无框 window 的 TitleBar,如下所示:
Rectangle {
id: root
width: parent.width
color: "#0099d6" // just random one
property QtObject container
// extra properties, maybe some signals
MouseArea {
id: titleBarMouseRegion
property var clickPos
anchors.fill: parent
onPressed: {
clickPos = { x: mouse.x, y: mouse.y }
}
onPositionChanged: {
container.x = mousePosition.cursorPos().x - clickPos.x
container.y = mousePosition.cursorPos().y - clickPos.y
}
}
}
4) 现在你已经准备好以任意方式使用此标题栏 window 接下来的方式:
Window {
id: root
visible: true
flags: Qt.FramelessWindowHint
TitleBar {
height: 20
container: root
}
Text {
text: qsTr("Hello World")
anchors.centerIn: parent
}
}
当我为标题栏实现拖放时,主要问题出在 QML 提供的代码中,此解决方案解决了该问题。
如果我的解决方案对您有帮助,请提供一些反馈。我真的很感兴趣:)
我有一个无框架的 ApplicationWindow,我想使用 this 问题的答案使其可拖动。然而,正如有人在评论中所说,当我快速移动 window 时,它会摇晃很多。
我一直在努力改进它,但没有成功。
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("WIP")
id: mainWindow
flags: Qt.SubWindow | Qt.Tool | Qt.FramelessWindowHint | Qt.WindowSystemMenuHint
header: ToolBar{
MouseArea{
anchors.fill: parent
onDoubleClicked: mainWindow.visibility!="2"?mainWindow.showNormal():mainWindow.showMaximized()
id: maMainWindow
property variant clickPos: "0,0"
onPressed: {
clickPos = Qt.point(mouse.x,mouse.y)
}
onPositionChanged: {
var delta = Qt.point(mouse.x-clickPos.x, mouse.y-clickPos.y)
mainWindow.x += delta.x;
mainWindow.y += delta.y;
}
}
}
}
如果我添加制表符和一些元素,情况会变得更糟。
C++ 能否以某种方式提高其性能?
我认为您无能为力,这只是使用绑定构建 GUI 的副作用,并且绑定评估与渲染不同步。结果,当您移动或调整 window 的大小时,所有内容都像弹性一样摆动,直到值 "catches up"。这是 QML 的事情,在小部件中你不会得到那种行为,因为 UI 不是围绕绑定构建的。基本上,每个绑定链的评估都有延迟,当 GUI 被绘制时,它捕获并显示绑定链传播的延迟,链中的第一个对象已经在它们的新位置,而那些更靠后的位置可能会在传播过程中落后几个步骤。当然,您的 window 是否有框架与该问题完全无关。
克服这个问题需要控制绑定处理信号的方式,我认为目前还没有这样的事情。基本上,诀窍是以某种方式强制绘图等待,直到链中的每个绑定都被评估,并在启动另一系列评估之前在两者之间绘制。
自然地,您拥有的元素越多,每次更改级联所有元素所需的时间就越长,从而使效果更加明显。它还取决于您的系统有多快 - 因为这决定了评估绑定链的延迟,例如我的系统很快并且您的示例代码不会产生抖动。然而,虽然在调整大小时发生这种情况是可以理解的,但它回避了为什么当您只是移动 window 时会发生这种情况的问题。毕竟,这不应该真正改变 window 中 UI 元素的相对位置。我怀疑发生这种情况是因为在内部这些对象是在 "absolute screen space" 中绘制的,因此当您移动 window 时,这会导致每个元素的实际绝对位置发生变化,即使它们相对于window,导致此行为。不理想...不仅引入了不良的视觉行为,而且引入了许多额外的评估,这些评估似乎是不必要的开销。
请注意,这些只是我模糊的怀疑,我还没有详细调查此事,希望有人能提供一种快速简便的方法来处理这个问题。现在我忽略了这个问题,希望它不会太烦人,考虑到我专注于与 window 的位置和几何形状的连续变化无关的软件;)顺便说一句,即使我第一次看到这在 QML 中,最近几年我在其他 "modern gui" 框架中也注意到了它。这是可以理解的,因为这样的框架为了快速原型制作而转向性能较慢的语言,并结合 "fluid" 异步非阻塞渲染。
我遇到了同样的问题,性能还可以,但是在 linux 上它在屏幕上跳来跳去 "jiggling"。我已经通过在 C++ 中编写一个助手 class 来解决它,我将其公开为 QML 上下文 属性。这个解决方案对我帮助很大。我有非常复杂的 UI,它工作得很好,性能非常好。 让我们开始吧。 1) 你需要一个帮手 class 像这样:
class CursorPosProvider : public QObject
{
Q_OBJECT
public:
explicit CursorPosProvider(QObject *parent = nullptr) : QObject(parent)
{
}
virtual ~CursorPosProvider() = default;
Q_INVOKABLE QPointF cursorPos()
{
return QCursor::pos();
}
};
这是一个非常简单的 class,它只是从 C++ 端为您提供光标位置,这很奇怪,但是当您在 QML 中执行相同操作时,您会遇到问题(至少在 linux 上) . 2) 将其作为上下文 属性 公开给 QML 引擎,我已经通过以下方式完成了:
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQuickView view;
CursorPosProvider mousePosProvider;
view.rootContext()->setContextProperty("mousePosition", &mousePosProvider);
view.setSource(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
3) 好的,现在我们准备好开始 QML 部分了。 我有一个 Qt Quick 组件,它实现了无框 window 的 TitleBar,如下所示:
Rectangle {
id: root
width: parent.width
color: "#0099d6" // just random one
property QtObject container
// extra properties, maybe some signals
MouseArea {
id: titleBarMouseRegion
property var clickPos
anchors.fill: parent
onPressed: {
clickPos = { x: mouse.x, y: mouse.y }
}
onPositionChanged: {
container.x = mousePosition.cursorPos().x - clickPos.x
container.y = mousePosition.cursorPos().y - clickPos.y
}
}
}
4) 现在你已经准备好以任意方式使用此标题栏 window 接下来的方式:
Window {
id: root
visible: true
flags: Qt.FramelessWindowHint
TitleBar {
height: 20
container: root
}
Text {
text: qsTr("Hello World")
anchors.centerIn: parent
}
}
当我为标题栏实现拖放时,主要问题出在 QML 提供的代码中,此解决方案解决了该问题。 如果我的解决方案对您有帮助,请提供一些反馈。我真的很感兴趣:)