pomo_mondreganto
pomo_mondreganto

Reputation: 2074

update NSView automatically with the function swift

I have a custom NSView with some drawing:

class ViewController: NSViewController {

@IBOutlet weak var mainView: LineDrawer!
var time = NSTimer()
override func viewDidLoad() {
    super.viewDidLoad()
    self.view.needsDisplay = true
    // Do any additional setup after loading the view.
}

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


}


class LineDrawer : NSView {
required init?(coder  aDecoder : NSCoder) {
    super.init(coder: aDecoder)
}

var lastPt : CGPoint!
var newPt : CGPoint!
var tmp = CGPoint()
override func viewWillDraw() {
    super.viewWillDraw()
    lastPt = newPt
}

override func drawRect(dirtyRect: NSRect) {
    super.drawRect(dirtyRect)
    self.needsDisplay = true
    NSColor.redColor().set()
    var newLinear = NSBezierPath()
    newLinear.moveToPoint(NSMakePoint(newPt.x, newPt.y))
    newLinear.lineToPoint(NSMakePoint(tmp.x, tmp.y))
    newLinear.lineWidth = 1
    newLinear.stroke()
    println(1)
}

override func mouseDown(theEvent: NSEvent) {
    super.mouseDown(theEvent)
    let location = theEvent.locationInWindow
    lastPt = theEvent.locationInWindow
    tmp = lastPt
}

override func mouseDragged(theEvent: NSEvent) {
    super.mouseDragged(theEvent)
    newPt = theEvent.locationInWindow
    self.drawRect(self.frame)
    tmp = newPt

}

}

It works, but lines appear only after hiding and bringing the window back. I'm looking for the code to write in updateTheView function to make the view update every time the mouseDragged is activated

Upvotes: 0

Views: 4699

Answers (3)

qwerty_so
qwerty_so

Reputation: 36295

You need to put the NSBezier stroke in the drawRect, not in the mouseDragged. Save the coordinates in mouseDragged in an instance array and then do the final drawing with Bezier in drawRect.

drawRect is called by the OS when the view needs display (either being told by needsDisplay = true from somewhere or when the window is moved). In the mouse-move routine just store the path. Then when it comes to drawing drawRect will actually draw the line.

class LineDrawer : NSView {
  var newLinear = NSBezierPath()

  override func drawRect(dirtyRect: NSRect) {
    NSColor.redColor().set()
    newLinear.lineWidth = 1
    newLinear.stroke()
  }

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

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

I tested it with a plain view in a window.

Upvotes: 2

TheCodingArt
TheCodingArt

Reputation: 3429

You're most likely not calling a method like setNeedsDisplay on the views to force a re drawing on the screen (this would be called when you hide/show the view again forcing the view to re draw itself). Here's a useful link if you don't know a view's life cycle that will help you with custom drawing:

raywenderlich custom controls

setNeedsDisplay()

Discussion Whenever the data or state used for drawing a view object changes, the view should be sent a setNeedsDisplay: message. NSView objects marked as needing display are automatically redisplayed on each pass through the application’s event loop. (View objects that need to redisplay before the event loop comes around can of course immediately be sent the appropriate display... method.)

Sample drawing iOS application

Upvotes: 1

Christian
Christian

Reputation: 22343

You can use the display() method to force the view to reload.

Just call that function on your main-view.

Documentation

If the receiver isn’t opaque, this method backs up the view hierarchy to the first opaque ancestor, calculates the portion of the opaque ancestor covered by the receiver, and begins displaying from there.

Upvotes: 0

Related Questions