Deleting From NSOutlineView With the Delete Key
cocoa (13), pyobjc (11)So lets say you're writing a PyObjC application, and you're deciding how you'll represent your data. You fire open a nib (xib, these days) and stare atNSTableView
andNSOutlineView
for a while before picking one of the two. Lets say you choseNSOutlineView
. You're going to need a way to create new nodes. Well, no sweat, just throw anNSButton
into the fray and use theNSAddTemplate
icon to make it clear what it does.
Here comes the big question though: how do you remove data from your shiny newNSOutlineView
? The easy answer is to add another button (perhaps with theNSRemoveTemplate
icon, you audacious rascal). If you're feeling really ambitious you may even bind a key to that button so that the delete key works.
Let a little time pass, though, and you'll start to have a nagging feeling. Something just doesn't feel right. You're never using that remove button, you're always pressing the delete key. Hell, once you meant to hit add and accidentally deleted something. You're finally ready to accept the truth: you just want to press the delete key, and you don't want no stinking remove button.
To accomplish that you'll need to subclassNSOutlineView
(或NSTableView
if thats what you're using). It'll look like this:
fromFoundationimport*classWRLOutlineView(NSOutlineView):defkeyDown_(self,event):key=event.charactersIgnoringModifiers()[0]flags=event.modifierFlags()&0x00FFiford(key)==127andflags==0:# Do your removal magic here.passelse:super(DeletableOutlineView,self).keyDown_(event)
Its a pretty simple trick, but can be a bit confusing to figure out. Specifically, it can be bewildering to try to figure out what non-textual characters are in Python. Here it was difficult to figure out how to reference the delete character so that I could check to see if the incoming key was a match. Thankfully the builtin functionord
turns ascii characters into their integer value, which made the comparison easy.
For completeness, here is the code I was using to actually remove the node from the table. At the line# Do your removal magic here.
I had the code:
self.delegate().removeList_(self)
I was using a custom datasource and delegate, and in the delegate theremoveList_
method looked like this:
@objc.IBActiondefremoveList_(self,sender):item=self.outlineView.itemAtRow_(self.outlineView.selectedRow())父=self.outlineView.父ForItem_(item)self.data.remove(item)self.outlineView.reloadItem_reloadChildren_(父,True)
In that snippetself.data
is an instance of a class containing my tree structure, andself.data.remove
is a method that will recursively search the tree structure to remove the node supplied as the argument.
I'll be continuing to scribble down these short PyObjC tips and tricks as I run into them, so let me know if there is anything you're particularly interested in looking at and I'll merrily investigate.
我总是s glad to hear your questions and comments.