0

I'm confused as to how I would implement a drag and drop ability for a window and then have the url appear in the textbox.

I've updated where I am stuck at

class controller(NSWindow):

#File to encode or decode
form_file = IBOutlet()
mainWindow = IBOutlet()


#drag and drop ability
def awakeFromNib(self):
    self.registerForDraggedTypes_([NSFilenamesPboardType, None])
    print 'registerd drag type'


def draggingEntered_(self, sender):
    print 'dragging entered doctor who'
    pboard = sender.draggingPasteboard()
    types = pboard.types()
    opType = NSDragOperationNone
    if NSFilenamesPboardType in types:
        opType = NSDragOperationCopy
    return opType


def performDragOperation_(self,sender):
    print 'preform drag operation'
    pboard = sender.draggingPasteboard()
    successful = False
    if NSFilenamesPboardType in pboard.types():
        print 'my actions finally working'
        fileAStr = pboard.propertyListForType_(NSFilenamesPboardType)[0]
        print type(fileAStr.encode('utf-8'))
        successful = True
    print self.form_file
    return successful

I can drop the file but I am unable to refrence the form_file outlet from inside of the performDragOperation function. As you can see I am attempting to print it but it returns a NoneType error.

(reason '<type 'exceptions.TypeError'>: 'NoneType' object is not callable') was raised during a dragging session

Cœur
  • 37,241
  • 25
  • 195
  • 267
lostAstronaut
  • 1,331
  • 5
  • 20
  • 34
  • Have you implemented the `draggingEntered:`, etc. methods? If not, you get the defaults, which always return `NSDragOperationNone`, which means nothing can be dropped. (You have read [Introduction to Drag and Drop](https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/DragandDrop/DragandDrop.html#//apple_ref/doc/uid/10000069i) in the documentation, right?) – abarnert Jan 09 '13 at 21:31
  • I did, I posted the code I got from a tutorial and yes I did read the documentation. I wondered if maybe I need an @IBAction or something. – lostAstronaut Jan 09 '13 at 21:34
  • Also, you may want to run Pasteboard Inspector from Julian Pellico, Pasteboard Peeker from the Xcode doc samples, Pasteboardtest from Heinrich Giesen, Drop Inspector from Philippe Mougin, or a similar tool (I don't have current links for any of them…) to see exactly what's being dropped, and make sure there is actually an `NSURLPboardType` to get. – abarnert Jan 09 '13 at 21:35
  • I feel like the problem isnt the pasteboard, i've been checking to make sure there is something on it, but that my window isn't accepting it. The code I posted was from an old tut which i feel may be out of date. When you drop a file in the textboxes they accept the url of the file and have a green plus next to the cursor but my window won't. – lostAstronaut Jan 09 '13 at 21:39
  • Can you paste the link to the tutorial you followed? – abarnert Jan 09 '13 at 21:39
  • first part of this http://lethain.com/epic-pyobjc-part-4-drag-drop-multiple-nibs/ – lostAstronaut Jan 09 '13 at 21:40
  • Also, one quick thing to try, which probably won't help: There are a some places where PyObjC doesn't automatically wrap the Python `list` `[a, b, c]` in `NSArray` `@[a, b, c, nil]` automatically, which means you have to manually pass `[a, b, c, None]`. – abarnert Jan 09 '13 at 21:41
  • Also, is it possible that the `NSView` is handing the drag messages before they even get to the `NSWindow`? Also, why do you have something called `controller` that's an `NSWindow` rather than an `NSWindowController` (or `NSViewController`, or whatever)? – abarnert Jan 09 '13 at 21:42
  • Ive actually tried using bot the view and window. This may just be due to lack of pyobjc experience but shouldn't I have to call these functions. In the example I posted I never did and they don't have an @IBAction. Im assuming theres some behind the scnenes work. – lostAstronaut Jan 09 '13 at 21:45
  • You don't need to call these functions; Cocoa sends `-[draggingEntered:]` to your `NSWindow`, and PyObjC accepts the message and dispatches it to `draggingEntered_()` on your Python subclass, just like it does with `-[awakeFromNib]`. (Is it printing your `'dragging entered doctor who'` message at all, or is Clara/Oswin erasing the message from your logs?) – abarnert Jan 09 '13 at 21:50
  • First, You are awesome for making that reference, and no Im not getting a print statement from any of the three. – lostAstronaut Jan 09 '13 at 21:55
  • Okay, my awakeFromNib had a typo in it, I fixed that so it now prints the registered d type (my message to see if that function was called). But I cant get the draggingEntered_ function to call. Could it be an issue with draggedTypes? – lostAstronaut Jan 09 '13 at 22:01
  • By `draggedType`, you mean the `list` you pass to `registerForDraggedTypes_`, right? Did you try adding the `None` to the end of the list as I suggested earlier? Otherwise, I don't think that's it. But I'm not sure what else it could be. Could you put the whole program up on github or something and post a link here? I'm not sure I'll have time to debug it, but even if I don't, someone else might. – abarnert Jan 09 '13 at 22:15
  • https://github.com/itom07/temp-pyobjc/blob/master/one.py Here it is, I literally have nothing else in the app apart from the IB because I've been trying to tackle this issue first. – lostAstronaut Jan 09 '13 at 22:26
  • How does the right window or view know it is the one with registerForDraggedTypes_? I look at that statement and I see nowhere which window it is linked to. – lostAstronaut Jan 09 '13 at 22:30
  • That goes by the normal Cocoa responder chain. Each responder can register for whatever it wants, but as soon as one responder handles it, the later ones don't get the chance to do so. (That's why I asked if you had a view that was rejecting the drop before the window ever got a chance.) – abarnert Jan 09 '13 at 22:40
  • Could the fact that my text field is active be preventing it? – lostAstronaut Jan 09 '13 at 22:56
  • Maybe. There are ways to debug the progress of messages through the responder chain, but an easier possibility is to just temporarily disable the register and the methods in the text field and see how that affects the window. – abarnert Jan 09 '13 at 23:03
  • I got the drag and drop working by going through your comments, any ideas regarding why I can't recognize the outlet? Oh and offer a answer and I'll accept it with all of the help you've given. – lostAstronaut Jan 10 '13 at 06:45
  • I don't see any access to `mainWindow`. Also, the exception looks like it's more than just not having the object you expect—it's not raising an error for trying to retrieve a member or call a method of an object that turned out to be `None`, but for trying to call `None` directly as a function. I'll add some more debugging tips to my answer, because I'm not sure where this is going wrong. – abarnert Jan 10 '13 at 19:46

1 Answers1

0

I believe your problem here was that something earlier in the Responder Chain was handling -[draggingEntered:] and rejecting the drag, before your window could get to it.

For a typical AppKit app, before getting to the window, an action message goes to the First Responder from the NIB, and anything hooked onto the back of it, then the innermost view and its delegate, then all of its ancestor views and their delegates. So if, for example, you have a text edit view that handles drag messages, and you drag over that view, the window won't see it.

Anyway, there are lots of ways to debug this, but the simplest one is to just have each method iterate the nextResponder() chain from self, printing (or logging.logging or NSLogging) the result. Then you can see who you're blocking.

Since there were a bunch of other issues we talked about in the comments, I'm not sure if this was the one that actually solved your problem. But one thing in particular to bring up:

I don't think PyObjC was part of the problem here. When the Cocoa runtime sends an ObjC message like -[draggingEntered:] to a PyObjC object, the PyObjC runtime handles that by looking for a draggingEntered_ method and converting it magically. (Well, I say magic, but it's simple science. Also, because it's sonic, it doesn't do wood.) You need @IBAction in the same places an ObjC program would need (IBAction), which are documented pretty well in the Cocoa documentation.

Meanwhile, one general-purpose debugging tip for PyObjC code (or just about any other event-loop-based or otherwise non-linear code). When you get an error like this:

(reason '<type 'exceptions.TypeError'>: 'NoneType' object is not callable') was raised     during a dragging session

It's hard to figure out what exactly went wrong. But you can handle the exception inside the function that raised, and get all the information you want. You can wrap a try/except around each line to figure out which line raised, you can print the whole traceback instead of just the summary, etc.

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • Someone edited my post, mainWindow works fine, I got the drag and drop working also, I was trying to update my textfield with the path of the file (iboutlet form_file) but I can't reference it. – lostAstronaut Jan 10 '13 at 20:11
  • But you're not calling either `self` or `form_file` here. You first need to narrow down where the exception is happening as I explained above, and then log all of the relevant objects to see which one isn't what it should be. – abarnert Jan 10 '13 at 20:19