How to code drawing a straight line with two mouse clicks (OSX Mac App)?

泪湿孤枕 提交于 2019-12-23 05:02:26

问题


I'm trying to make a simple drawing app (OSX Mac app) and I'm trying to figure out how the user can draw a line by two mouse clicks, for example, the first mouse click (mouseDown then mouseUP) would mark the origin point of the line, and the second mouse click (mouseDown then mouseUP) would mark the end point of the line. Before the user makes the second click of the end point, I'd like the line (before anchoring the end point) to be shown live, kind of like in photoshop. Both Objective-C and Swift are fine.

So far I've got...

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
    }

Cheers!


回答1:


enums with associated values are great for this as your application scales up and possibly adds other tools and states.

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`
    }
}



回答2:


I understand what you are attempting to achieve here! So I have added lines of code to the andyvn22's solution that should assist your endeavours, please note: for simplicity purposes start a new 'Xcode Project' and we can make sure everything is covered together.

In your new project Right Click 'ViewController.swift' and add New File... Select 'Cocoa Class' and Click Next, name this file 'DrawingView' assure Subclass of: is 'NSView' and select Next.

Now your finished that lets setup your interface, enter 'Main.storyboard' and drag/drop a 'Custom View' make sure to add constrains according to your preferences. Now enter your 'Identity Inspector' while 'Custom View' is selected and add 'DrawingView' to Class at the top.

I hope this is making sense soo far! Ok open 'Assistant Editor' so you can view 'ViewController.swift' and 'Main.storyboard' simultaneously, Right Click and drag from 'Custom View' to 'ViewController.swift', name this 'draw' and select connect.

You will notice Xcode has automatically updated @IBOutlet to your Subclass, and your 'ViewController.swift' looks like the example below.

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.
        }
    }
}

Now select the 'DrawingView.swift' file and clear all content on page, highlight the code below, copy and paste into your project.

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)
        }
    }
}

Everything should be running as intended, you will be incapable of drawing a crocked line. I hope this has helped and feel free to reply for additional information.



来源:https://stackoverflow.com/questions/38222054/how-to-code-drawing-a-straight-line-with-two-mouse-clicks-osx-mac-app

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!