You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Qt3D(QML)中实现撤销/重做(Undo/Redo)操作

实现方案

1. 删除指定Entity

你当前通过NodeInstantiator绑定ListModel生成实体,实体的生命周期完全和Model条目对应,删除指定实体只需操作Model即可。
如果需要实现点击选中删除的能力,只需要在实体的delegate中增加拾取组件:

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)
        },
        // 新增拾取组件
        ObjectPicker {
            onClicked: {
                // NodeInstantiator会为每个delegate自动附加index属性,对应Model中的条目索引
                entityModel.remove(sphereEntity.index)
                // 如果需要支持撤销删除操作,可在此处将删除的条目存入撤销栈,同步调整栈逻辑即可
            }
        }
    ]
}

如果只需要删除最后创建的实体,直接调用entityModel.remove(entityModel.count - 1)即可。

2. 撤销/重做功能实现

核心逻辑

用两个数组分别作为撤销栈和重做栈:

  • 每次新增球体时,将本次新增的参数压入撤销栈,同时清空重做栈
  • 触发Ctrl+Z撤销时,弹出撤销栈最后一条记录压入重做栈,删除Model最后一条条目
  • 触发Ctrl+Shift+Z重做时,弹出重做栈最后一条记录压入撤销栈,将参数重新添加到Model中

代码修改

首先在RootEntity根节点下新增两个属性存储栈结构:

property var undoStack: []
property var redoStack: []

修改MouseHandler的点击新增逻辑,同步操作栈:

onPressed:
{
    x++;
    let newItem = {"x":x,"y":0.0,"z": Math.random()}
    entityModel.append(newItem)
    undoStack.push(newItem)
    redoStack = [] // 新增操作后清空重做栈
}

在RootEntity根节点下新增快捷键处理逻辑(你的Scene3D已经开启了focus: true,可以正常接收按键事件):

Keys.onPressed: {
    if (event.modifiers & Qt.ControlModifier) {
        if (event.key === Qt.Key_Z) {
            if (event.modifiers & Qt.ShiftModifier) {
                // 重做 Ctrl+Shift+Z
                if (redoStack.length > 0) {
                    let item = redoStack.pop()
                    entityModel.append(item)
                    undoStack.push(item)
                    x = item.x // 同步全局x计数
                }
            } else {
                // 撤销 Ctrl+Z
                if (undoStack.length > 0) {
                    let item = undoStack.pop()
                    redoStack.push(item)
                    entityModel.remove(entityModel.count - 1)
                    x = undoStack.length ? undoStack[undoStack.length -1].x : 0
                }
            }
            event.accepted = true
        }
    }
}

内容的提问来源于stack exchange,提问作者Parisa.H.R

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.16 20:45:05