macOS/Cocoa Drag-n-Drop

I have been searching for a simple example literally all day, and can’t find anything :frowning:

I need a simple Swift (ObjC if I must) example of how to “drag” from one part of the screen to another. All I can find is draggin files/photos etc from outside into an App.

Techinically I’m not really “moving” anything. When I do mousedown, I need to get the ID of the NSView I’m in, “drag” to another NSView and “drop” the ID.

Think of the Xojo Toolbox… you “pick up” a control, and drop it on the design canvas. Same idea.

Anyone know of any examples I can work from…

Its interesting to see how powerful Swift is, but how much Xojo has enscapsulated.

Google for “swift drag and drop control”

and you get quite a few, eg

Markus… trust me I have done that… 100’s and 100’s of times…
The results are for dragging files from Finder, Photos from Finder, dragging between apps, and 100% of them require the embedded use of Interface Builder.

FYI… NSVIEW is a Swift macOS construct… the example you pointed to was UIKit (ie. iOS… and macOS has a vastly different paradigm from iOS for a lot of things (unfortunately)

But thanks :slight_smile:

Forgive me if you’ve already seen this one, but this article seems to deal with drag/drop of controls within an app as well as from an outside source, (my guess is there’s not much difference).

Thanks… I have a huge problem with RayWenderlich tutorials.

Everyone I have read so far presents a super fancy overly complex approach that ends up hiding the solution inside a bunch of bells and whistles…

but so far this seems to be where I have to start.

Perhaps I can take that demo, and rip out all the glitter (and IB stuff)

FYI… that demo is no longer supported (written in Swift 3)
SOooooo… I have to figure how to update it, without yet understanding how it works

not to mention it have places where code was left out…

Basicly all I need to do is MOUSEDOWN on NSView#1 and detect that I MouseUP on NSView#2 … I guess I can fake the rest…

Apple macOS docs are terrible at best

The macOS docs have gotten worse
As if all they do is scan the header files for comments from devs who write very little

This doesnt help at all ?

I try to avoid Apple’s docs as much as possible… They provide zero context. So you don’t know where to put things…

And everyone else posts “snippets” of code, again totally out of context… SO you need to know the solution in order to implement the solution.

So far I have spent TWO full days on something that SHOULD be easy-peasy, and probably will be if I can figure it out. :frowning:

Unfortunately all I can say is “I totally agree”

Apples docs have gotten worse and worse and decent samples grown fewer and fewer

Ok… have a partial solution (FINALLY)… the cursor changes, and it picks up the string I want and delivers it to the correct object…
It uses the UIImage of the NSView as the drag item!

In the SOURCE View (in my case an NSVIEW)

  • add NSDraggingSource as a delegate
  • next add registerForDraggedTypes([.string]) in the INIT method
  • finally add
  internal override func mouseDown(with event: NSEvent) {
        self.delegate?.cellClick(self ,index:self.index)
        let pasteboardItem = NSPasteboardItem()
        pasteboardItem.setString(zText!.stringValue, forType:.string)
        let draggingItem = NSDraggingItem(pasteboardWriter: pasteboardItem)
        draggingItem.setDraggingFrame(self.bounds, contents:self)
        beginDraggingSession(with: [draggingItem], event: event, source: self.zIcon.image)

    func draggingSession(_ session: NSDraggingSession, sourceOperationMaskFor context: NSDraggingContext) -> NSDragOperation {
        switch(context) {
        case .withinApplication  : return .generic
        default : return NSDragOperation()

zText! contains the string I want to pass (its different in each instance of the NSVIew

In the DESTINATION (here its a NSSCrollView [for now])

  • add registerForDraggedTypes([.string]) in the INIT method
  • then add
 override func draggingUpdated(_ sender: NSDraggingInfo) -> NSDragOperation { return .copy }
    override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation { return .copy }
    override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
        let droppedString : String = sender.draggingPasteboard.string(forType: .string)!
       let point = convert(sender.draggingLocation, from: nil)
        print("drop=\(droppedString) at \(point))")
        return true
1 Like