如何在 Qt3D 中创建撤消/重做操作? [关闭]

Posted

技术标签:

【中文标题】如何在 Qt3D 中创建撤消/重做操作? [关闭]【英文标题】:How to create Undo/Redo operations in Qt3D? [closed] 【发布时间】:2021-06-13 07:57:34 【问题描述】:

我在 QML 中使用 qt3d 创建了一些实体。例如,此代码显示了一个声明 RootEntityScene3D 元素,这是另一个包含场景图的 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+ZCtrl+Shift+Z。 谢谢。

【问题讨论】:

你的问题太宽泛了。 undo 意味着您对实体执行了一些转换,但您的问题中没有任何内容。请澄清问题并提供minimal reproducible example,以便我们运行和测试它。 你必须自己实现它。请阅读Overview of Qt's Undo Framework 页面了解更多信息。要从ListModel 中删除元素,您可以使用ListModel.remove 方法。 【参考方案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 。谢谢大家的回复。

以上是关于如何在 Qt3D 中创建撤消/重做操作? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

如何与浏览器 control+z/control+y 交互以进行撤消/重做?

如何将Tkinter Text小部件的撤消/重做历史记录复制到另一个小部件中

撤消 CGLayer 的重做问题

在 CoreData 应用程序上摇动撤消工作,但没有显示撤消/重做提示

检测 iOS 13 撤消和重做

使用vuex在对象数组上执行撤消/重做