如何在 Qt3D 中创建撤消/重做操作? [关闭]
Posted
技术标签:
【中文标题】如何在 Qt3D 中创建撤消/重做操作? [关闭]【英文标题】:How to create Undo/Redo operations in Qt3D? [closed] 【发布时间】:2021-06-13 07:57:34 【问题描述】:我在 QML 中使用 qt3d 创建了一些实体。例如,此代码显示了一个声明 RootEntity
的 Scene3D
元素,这是另一个包含场景图的 QML 元素:
Scene3D
id : scene3d
anchors.fill: parent
focus: true
aspects: ["render", "logic", "input"]
hoverEnabled: true
cameraAspectRatioMode: Scene3D.AutomaticAspectRatio
antialiasing: true
RootEntity
id:root
RootEntity.qml:
Entity
id:root
property double x : 0.0
Camera
id: mainCamera
projectionType: CameraLens.PerspectiveProjection
fieldOfView: 45
aspectRatio: 16/9
nearPlane : 0.1
farPlane : 1000.0
position: Qt.vector3d(0.0, 4.49373, -3.78577)
upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
viewCenter: Qt.vector3d(0.0, 0.5, 0.0)
OrbitCameraController
id: mainCameraController
camera: mainCamera
components: [
RenderSettings
Viewport
normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0)
RenderSurfaceSelector
CameraSelector
id: cameraSelector
camera: mainCamera
FrustumCulling
ClearBuffers
buffers: ClearBuffers.AllBuffers
clearColor: "#444449"
NoDraw
LayerFilter
filterMode: LayerFilter.DiscardAnyMatchingLayers
layers: [topLayer]
LayerFilter
filterMode: LayerFilter.AcceptAnyMatchingLayers
layers: [topLayer]
ClearBuffers
buffers: ClearBuffers.DepthBuffer
,
InputSettings
]
Layer
id: topLayer
recursive: true
ListModel
id: entityModel
ListElement x:0;y:0;z:0
NodeInstantiator
id:instance
model: entityModel
delegate: Entity
id: sphereEntity
components: [
SphereMesh
id:sphereMesh
radius: 0.3
,
PhongMaterial
id: materialSphere
ambient:"red"
,
Transform
id: transform
translation:Qt.vector3d(x, y, z)
]
MouseDevice
id: mouseDev
MouseHandler
id: mouseHandler
sourceDevice: mouseDev
onPressed:
x++;
entityModel.append("x":x,"y":0.0,"z": Math.random())
在我的 Scene3D 中单击鼠标时,会显示一个球体。
我不知道如何通过按 Ctrl+Z 和 Ctrl+Shift+Z。 谢谢。
【问题讨论】:
你的问题太宽泛了。 undo 意味着您对实体执行了一些转换,但您的问题中没有任何内容。请澄清问题并提供minimal reproducible example,以便我们运行和测试它。 你必须自己实现它。请阅读Overview of Qt's Undo Framework 页面了解更多信息。要从ListModel
中删除元素,您可以使用ListModel.remove 方法。
【参考方案1】:
一种方法是维护Qt.vector3d
元素的全局列表,并使用它来记录通过“撤消”操作移除的球体的位置:
Qt.vector3d
对象来存储最后渲染的球体的位置(即最后一个球体)附加到 entityModel
) 并将该位置添加到 3d 向量的全局列表中;
然后,要从屏幕上删除一个球体,请调用entityModel.remove()
并使用需要擦除的球体的索引;
“重做”操作正好相反:
当用户点击 CTRL+Y 时,全局 3d 向量列表的最后一个元素保存最新移除的球体的位置:将此位置附加到 @987654327 @ 所以球体可以再次渲染; 然后,请记住从全局列表中删除此位置,以便下一次撤消操作可以渲染不同的球体;RootEntity.qml:
import QtQuick 2.0
import QtQml.Models 2.15
import Qt3D.Core 2.12
import Qt3D.Render 2.12
import Qt3D.Extras 2.12
import Qt3D.Input 2.12
Entity
id: root
// global list of Qt.vector3d elements that store the location of the spheres that are removed
property variant removedSpheres : []
// x-coordinate of the next sphere that will be added
property double x : 0.0
Camera
id: mainCamera
projectionType: CameraLens.PerspectiveProjection
fieldOfView: 45
aspectRatio: 16/9
nearPlane : 0.1
farPlane : 1000.0
position: Qt.vector3d(0.0, 4.49373, -3.78577)
upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
viewCenter: Qt.vector3d(0.0, 0.5, 0.0)
OrbitCameraController
id: mainCameraController
camera: mainCamera
components: [
RenderSettings
Viewport
normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0)
RenderSurfaceSelector
CameraSelector
id: cameraSelector
camera: mainCamera
FrustumCulling
ClearBuffers
buffers: ClearBuffers.AllBuffers
clearColor: "#444449"
NoDraw
LayerFilter
filterMode: LayerFilter.DiscardAnyMatchingLayers
layers: [topLayer]
LayerFilter
filterMode: LayerFilter.AcceptAnyMatchingLayers
layers: [topLayer]
ClearBuffers
buffers: ClearBuffers.DepthBuffer
,
InputSettings
]
Layer
id: topLayer
recursive: true
ListModel
id: entityModel
ListElement x: 0; y: 0; z: 0
NodeInstantiator
id: instance
model: entityModel
delegate: Entity
id: sphereEntity
components: [
SphereMesh id:sphereMesh; radius: 0.3 ,
PhongMaterial id: materialSphere; ambient:"red" ,
Transform id: transform; translation:Qt.vector3d(x, y, z)
]
MouseDevice
id: mouseDev
MouseHandler
id: mouseHandler
sourceDevice: mouseDev
onPressed:
if (mouse.button === Qt.LeftButton)
console.log("LeftButton: new sphere")
// add new sphere
entityModel.append( "x" : ++root.x, "y" : 0.0, "z" : Math.random() )
if (mouse.button === Qt.MiddleButton)
console.log("MiddleButton: clear spheres")
// removes all spheres (can't be undone)
root.x = 0;
entityModel.clear();
removedSpheres.length = 0;
KeyboardDevice
id: keyboardDev
KeyboardHandler
id: keyboardHandler
sourceDevice: keyboardDev
focus: true
onPressed:
// handle CTRL+Z: undo
if (event.key === Qt.Key_Z && (event.modifiers & Qt.ControlModifier))
console.log("CTRL+Z")
// remove the last sphere added to the screen
let lastIdx = entityModel.count - 1;
if (lastIdx >= 0)
// save sphere position before removal
removedSpheres.push(Qt.vector3d(entityModel.get(lastIdx).x, entityModel.get(lastIdx).y, entityModel.get(lastIdx).z));
// remove sphere from the model
entityModel.remove(lastIdx);
// handle CTRL+Y: redo
if (event.key === Qt.Key_Y && (event.modifiers & Qt.ControlModifier))
console.log("CTRL+Y")
// add the last sphere removed back into the model
if (removedSpheres.length > 0)
// add the sphere
let lastIdx = removedSpheres.length - 1;
entityModel.append( "x" : removedSpheres[lastIdx].x, "y" : removedSpheres[lastIdx].y, "z" : removedSpheres[lastIdx].z )
// erase the last item added to removedSpheres
removedSpheres.pop()
【讨论】:
也许值得一提(没有示例实现)还有Qt Undo System :) 可能有点矫枉过正,但知道它存在总是好的。 我知道有Qt Undo System。但这是针对小部件的。当我们使用小部件时,它需要 QT += 小部件并且可以工作。 现在我使用 qt3d 。我的基础对象是 scene3d 。谢谢大家的回复。以上是关于如何在 Qt3D 中创建撤消/重做操作? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章
如何与浏览器 control+z/control+y 交互以进行撤消/重做?
如何将Tkinter Text小部件的撤消/重做历史记录复制到另一个小部件中