【问题标题】:How to code drawing a straight line with two mouse clicks (OSX Mac App)?如何通过两次鼠标单击(OSX Mac App)编码绘制一条直线?
【发布时间】:2023-03-31 20:02:02
【问题描述】:

我正在尝试制作一个简单的绘图应用程序(OSX Mac 应用程序),并且我试图弄清楚用户如何通过两次鼠标单击来绘制一条线,例如,第一次鼠标单击(mouseDown 然后 mouseUP)将标记线的起点,第二次鼠标单击(mouseDown 然后 mouseUP)将标记线的终点。在用户第二次单击终点之前,我希望线(在锚定终点之前)实时显示,有点像在 Photoshop 中。 Objective-C 和 Swift 都很好。

到目前为止,我已经...

var newLinear = NSBezierPath()

override func mouseDown(theEvent: NSEvent) {
        super.mouseDown(theEvent)
        var lastPoint = theEvent.locationInWindow
        lastPoint.x -= frame.origin.x
        lastPoint.y -= frame.origin.y
        newLinear.moveToPoint(lastPoint)
    }

override func mouseUp(theEvent: NSEvent) {
        var newPoint = theEvent.locationInWindow
        newPoint.x -= frame.origin.x
        newPoint.y -= frame.origin.y
        newLinear.lineToPoint(newPoint)
        needsDisplay = true
    }

干杯!

【问题讨论】:

  • 使用二进制状态机var gotFirstPoint = false,如果false在mouseClick上设置它true并保存原点,如果true在mouseMove中检查值并重绘,如果@则在mouseClick中完成线987654326@?
  • 到目前为止,我可以通过拖动来绘制线条,但即使在拖动时,我也看不到线条。我想实时显示我拖动的线条。
  • 在 mouseMove 例程中,您需要捕获终点并设置视图的needsDisplay,然后在drawRect 中检查您当前是否正在拖动,如果是则绘制线。应该工作得很好......
  • 查看示例应用 Sketch。
  • 如果我有源代码,那就太好了。

标签: objective-c swift macos nsview


【解决方案1】:

带有关联值的enums 非常适合您的应用程序扩展并可能添加其他工具和状态。

enum State {
    case normal
    case drawingLine(from: CGPoint, to: CGPoint)
}
var state = State.normal

override func mouseDown(theEvent: NSEvent) {
    super.mouseDown(theEvent)
    var lastPoint = theEvent.locationInWindow
    lastPoint.x -= frame.origin.x
    lastPoint.y -= frame.origin.y
    state = .drawingLine(from: lastPoint, to: lastPoint)
}

override func mouseUp(theEvent: NSEvent) {
    if case .drawingLine(let firstPoint, _) = state {
        var newPoint = theEvent.locationInWindow
        newPoint.x -= frame.origin.x
        newPoint.y -= frame.origin.y
        //finalize line from `firstPoint` to `newPoint`
    }
}

override func mouseMoved(theEvent: NSEvent) {
    if case .drawingLine(let firstPoint, _) = state {
        needsDisplay = true
        var newPoint = theEvent.locationInWindow
        newPoint.x -= frame.origin.x
        newPoint.y -= frame.origin.y
        state = .drawingLine(from: firstPoint, to: newPoint)
    }
}

override func draw(_ dirtyRect: NSRect) {
    if case .drawingLine(let firstPoint, let secondPoint) = state {
        //draw your line from `firstPoint` to `secondPoint`
    }
}

【讨论】:

  • 感谢您的回复和yvn22。我已经尝试过您的代码,但我无法让它工作。代码看起来真的很棒,但我还是个初学者,所以我想知道你是否可以在这方面进一步帮助我?干杯!
  • 没问题——如果你能确定是什么给你带来了麻烦,你可以提出一个新的问题(是如何在覆盖的draw(_:)中画一条线?)或者也许找到一个已经 -已回答问题。
【解决方案2】:

我了解您在这里尝试实现的目标!因此,我在 andyvn22 的解决方案中添加了几行代码,这应该有助于您的工作,请注意:为简单起见,开始一个新的“Xcode 项目”,我们可以确保所有内容都包含在一起。

在您的新项目中右键单击“ViewController.swift”并添加新文件...选择“Cocoa Class”并单击“下一步”,将此文件命名为“DrawingView”,确保子类为“NSView”并选择“下一步”。

现在您已完成设置界面,输入“Main.storyboard”并拖放“自定义视图”,确保根据您的偏好添加约束。现在输入您的“Identity Inspector”,同时选择“Custom View”并将“DrawingView”添加到顶部的 Class。

我希望到目前为止这是有道理的!好的,打开“Assistant Editor”,这样您就可以同时查看“ViewController.swift”和“Main.storyboard”,右键单击并从“Custom View”拖动到“ViewController.swift”,将其命名为“draw”并选择“connect”。

您会注意到 Xcode 已自动将 @IBOutlet 更新为您的子类,并且您的“ViewController.swift”看起来像下面的示例。

import Cocoa

class ViewController: NSViewController {

    @IBOutlet var draw: DrawingView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    override var representedObject: Any? {
        didSet {
        // Update the view, if already loaded.
        }
    }
}

现在选择“DrawingView.swift”文件并清除页面上的所有内容,突出显示下面的代码,复制并粘贴到您的项目中。

import Cocoa

class DrawingView: NSView {

    // >>>CODE ADDED BY LC<<<
    private var path: NSBezierPath = {
        let path = NSBezierPath()
        path.lineWidth = 50.0
        path.lineJoinStyle = .roundLineJoinStyle
        path.lineCapStyle = .roundLineCapStyle
        return path
    }()

    enum State {
        case normal
        case drawingLine(from: CGPoint, to: CGPoint)
    }
    var state = State.normal

    override func mouseDown(with event: NSEvent) {
        super.mouseDown(with: event)
        var lastPoint = event.locationInWindow
        lastPoint.x -= frame.origin.x
        lastPoint.y -= frame.origin.y
        state = .drawingLine(from: lastPoint, to: lastPoint)
    }

    override func mouseUp(with event: NSEvent) {
        if case .drawingLine(let firstPoint, _) = state {
            var newPoint = event.locationInWindow
            newPoint.x -= frame.origin.x
            newPoint.y -= frame.origin.y

            // >>>CODE ADDED BY LC<<<
            path.move(to: convert(event.locationInWindow, from: nil))
            path.line(to: firstPoint)
            needsDisplay = true
        }
    }

    override func draw(_ dirtyRect: NSRect) {
        if case .drawingLine(let firstPoint, let secondPoint) = state {

            // >>>CODE ADDED BY LC<<<
            NSColor.orange.set()
            path.lineWidth = 5.0
            path.stroke()
            path.line(to: firstPoint)
            path.line(to: secondPoint)
        }
    }
}

一切都应该按预期运行,您将无法画出一条弯曲的线。我希望这对您有所帮助,并随时回复以获取更多信息。

【讨论】:

    猜你喜欢
    • 2012-08-28
    • 1970-01-01
    • 2018-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-30
    相关资源
    最近更新 更多