【问题标题】:How to create Undo/Redo operations in Qt3D? [closed]如何在 Qt3D 中创建撤消/重做操作? [关闭]
【发布时间】: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 方法。

标签: qt qml qt3d


【解决方案1】:

一种方法是维护Qt.vector3d 元素的全局列表,并使用它来记录通过“撤消”操作移除的球体的位置:

  • 当用户点击 CTRL+Z 时,创建一个新的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 。谢谢大家的回复。
猜你喜欢
  • 1970-01-01
  • 2018-08-23
  • 2011-04-02
  • 2010-12-10
  • 2012-06-22
  • 1970-01-01
  • 1970-01-01
  • 2023-03-23
  • 1970-01-01
相关资源
最近更新 更多