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

在Mac OS X中用Swift 4为NSBezierPath添加NSUndoManager撤销功能

实现NSBezierPath圆形绘制的撤销功能

嘿,我来帮你搞定这个撤销功能的实现!要给你的圆形绘制操作加上撤销能力,核心思路就是追踪每一次绘制的图层,在需要撤销的时候把最后一次添加的图层从视图中移除。下面是具体的分步实现:

1. 先在ViewController中添加操作追踪数组

首先在你的NSViewController类里定义一个数组,用来保存所有绘制出来的CAShapeLayer,这样我们能记住每一步的绘制操作:

private var drawnLayers: [CAShapeLayer] = []

2. 改造你的绘制方法,完成圆形绘制并记录图层

调整bezierPathMouseUndoTest方法,修正圆形的位置计算(让鼠标位置成为圆心),并把创建好的图层存入追踪数组:

func bezierPathMouseUndoTest(mouseLocation: CGPoint, color: NSColor) {
    // 以鼠标位置为圆心,45为半径创建圆形路径
    let circlePath = NSBezierPath(ovalIn: CGRect(
        x: mouseLocation.x - 45,
        y: mouseLocation.y - 45,
        width: 90,
        height: 90
    ))
    
    // 配置CAShapeLayer的样式
    let shapeLayer = CAShapeLayer()
    shapeLayer.path = circlePath.cgPath
    shapeLayer.fillColor = color.cgColor
    shapeLayer.strokeColor = NSColor.black.cgColor
    shapeLayer.lineWidth = 2
    
    // 将图层添加到视图
    view.layer?.addSublayer(shapeLayer)
    
    // 把这个图层存入数组,用于后续撤销操作
    drawnLayers.append(shapeLayer)
}

注:原来的CGRect(x:0,y:0,width:100,height:100)会把圆形固定在左上角,这里调整后圆形的圆心就是传入的鼠标位置,符合你的需求。

3. 实现撤销方法

添加一个专门的撤销方法,移除最后一次绘制的圆形:

func undoLastCircle() {
    // 取出最后一个绘制的图层(如果有的话)
    guard let lastDrawnLayer = drawnLayers.popLast() else {
        // 没有可撤销的操作,直接返回
        return
    }
    // 从视图中移除该图层
    lastDrawnLayer.removeFromSuperlayer()
}

4. 触发撤销的方式

你可以通过多种方式触发这个撤销方法,举两个常用的例子:

方式一:绑定按钮点击

给界面上的“撤销”按钮添加点击事件,直接调用undoLastCircle()即可。

方式二:支持快捷键(Command+Z)

重写ViewController的keyDown方法,监听Command+Z组合键:

override func keyDown(with event: NSEvent) {
    // 检查是否是Command+Z组合键(Z键的keyCode是6)
    if event.modifierFlags.contains(.command) && event.keyCode == 6 {
        undoLastCircle()
    } else {
        super.keyDown(with: event)
    }
}

额外扩展:重做功能(可选)

如果需要支持重做,可以再添加一个数组记录被撤销的图层:

private var undoneLayers: [CAShapeLayer] = []

// 修改撤销方法
func undoLastCircle() {
    guard let lastDrawnLayer = drawnLayers.popLast() else { return }
    lastDrawnLayer.removeFromSuperlayer()
    undoneLayers.append(lastDrawnLayer)
}

// 添加重做方法
func redoLastCircle() {
    guard let lastUndoneLayer = undoneLayers.popLast() else { return }
    view.layer?.addSublayer(lastUndoneLayer)
    drawnLayers.append(lastUndoneLayer)
}

内容的提问来源于stack exchange,提问作者Oblivion access

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:01:23