我试图了解如何最好地将文件从Finder拖放到NSTableView,随后将列出这些文件。
我已经建立了一个小测试应用程序作为试验场。
目前我有一个带有FileListController NSTableView作为它的数据。 它基本上是File对象的NSMutableArray。
我正在尝试找出最佳/正确的方法来实现NSTableView的拖放代码。
我的第一种方法是子类化NSTableView并实现所需的方法:
TableViewDropper.h
#import <Cocoa/Cocoa.h> @interface TableViewDropper : NSTableView @endTableViewDropper.m
#import "TableViewDropper.h" @implementation TableViewDropper { BOOL highlight; } - (id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { // Initialization code here. NSLog(@"init in initWithCoder in TableViewDropper.h"); [self registerForDraggedTypes:@[NSFilenamesPboardType]]; } return self; } - (BOOL)performDragOperation:(id < NSDraggingInfo >)sender { NSLog(@"performDragOperation in TableViewDropper.h"); return YES; } - (BOOL)prepareForDragOperation:(id)sender { NSLog(@"prepareForDragOperation called in TableViewDropper.h"); NSPasteboard *pboard = [sender draggingPasteboard]; NSArray *filenames = [pboard propertyListForType:NSFilenamesPboardType]; NSLog(@"%@",filenames); return YES; } - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender { highlight=YES; [self setNeedsDisplay: YES]; NSLog(@"drag entered in TableViewDropper.h"); return NSDragOperationCopy; } - (void)draggingExited:(id)sender { highlight=NO; [self setNeedsDisplay: YES]; NSLog(@"drag exit in TableViewDropper.h"); } -(void)drawRect:(NSRect)rect { [super drawRect:rect]; if ( highlight ) { //highlight by overlaying a gray border [[NSColor greenColor] set]; [NSBezierPath setDefaultLineWidth: 18]; [NSBezierPath strokeRect: rect]; } } @enddraggingEntered和draggingExited方法都被调用,但prepareForDragOperation和performDragOperation没有。 我不明白为什么不呢?
接下来我想我将继承NSTableView的ClipView。 因此,使用与上面相同的代码,只是将头文件中的类类型转换为NSClipView,我发现prepareForDragOperation和performDragOperation现在按预期工作,但ClipView没有突出显示。
如果我将NSScrollView子类化,则调用所有方法并突出显示但不是必需的。 它非常薄,正如预期的那样围绕着整个NSTableView而不仅仅是我想要的表头下面的位。
所以我的问题是sublclass是什么是正确的,我需要什么方法,这样当我从Finder执行拖放操作时,ClipView会正确地突出显示并调用prepareForDragOperation和performDragOperation 。
并且当performDragOperation成功时,该方法如何调用我的FileListController中的方法,告诉它创建一个新的File对象并将其添加到NSMutableArray?
I'm trying to understand how best to impliment drag and drop of files from the Finder to a NSTableView which will subsequently list those files.
I've built a little test application as a proving ground.
Currently I have a single NSTableView with FileListController as it's datasourse. It's basically a NSMutableArray of File objects.
I'm trying to work out the best / right way to impliment the drag and drop code for the NSTableView.
My first approach was to subclass the NSTableView and impliment the required methods :
TableViewDropper.h
#import <Cocoa/Cocoa.h> @interface TableViewDropper : NSTableView @endTableViewDropper.m
#import "TableViewDropper.h" @implementation TableViewDropper { BOOL highlight; } - (id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { // Initialization code here. NSLog(@"init in initWithCoder in TableViewDropper.h"); [self registerForDraggedTypes:@[NSFilenamesPboardType]]; } return self; } - (BOOL)performDragOperation:(id < NSDraggingInfo >)sender { NSLog(@"performDragOperation in TableViewDropper.h"); return YES; } - (BOOL)prepareForDragOperation:(id)sender { NSLog(@"prepareForDragOperation called in TableViewDropper.h"); NSPasteboard *pboard = [sender draggingPasteboard]; NSArray *filenames = [pboard propertyListForType:NSFilenamesPboardType]; NSLog(@"%@",filenames); return YES; } - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender { highlight=YES; [self setNeedsDisplay: YES]; NSLog(@"drag entered in TableViewDropper.h"); return NSDragOperationCopy; } - (void)draggingExited:(id)sender { highlight=NO; [self setNeedsDisplay: YES]; NSLog(@"drag exit in TableViewDropper.h"); } -(void)drawRect:(NSRect)rect { [super drawRect:rect]; if ( highlight ) { //highlight by overlaying a gray border [[NSColor greenColor] set]; [NSBezierPath setDefaultLineWidth: 18]; [NSBezierPath strokeRect: rect]; } } @endThe draggingEntered and draggingExited methods both get called but prepareForDragOperation and performDragOperation don't. I don't understand why not?
Next I thought I'll subclass the ClipView of the NSTableView instead. So using the same code as above and just chaging the class type in the header file to NSClipView I find that prepareForDragOperation and performDragOperation now work as expected, however the ClipView doesn't highlight.
If I subclass the NSScrollView then all the methods get called and the highlighting works but not as required. It's very thin and as expected round the entire NSTableView and not just the bit below the table header as I'd like.
So my question is what is the right thing to sublclass and what methods do I need so that when I peform a drag and drop from the Finder, the ClipView highlights properly and prepareForDragOperation and performDragOperation get called.
And also when performDragOperation is successful how can this method call a method within my FileListController telling it to create a new File object and adding it to the NSMutableArray?
最满意答案
回答我自己的问题。
似乎继承NSTableView(不是NSScrollView或NSClipView)是正确的方法。
在子类中包含此方法:
- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender { return [self draggingEntered:sender]; }解决了未调用prepareForDragOperation和performDragOperation的问题。
要允许您在控制器类中调用方法,可以将NSTextView的delagate作为控制器。 在这种情况下FileListController 。
然后在NSTableView子类的performDragOperation中使用类似下面的内容:
NSPasteboard *pboard = [sender draggingPasteboard]; NSArray *filenames = [pboard propertyListForType:NSFilenamesPboardType]; id delegate = [self delegate]; if ([delegate respondsToSelector:@selector(doSomething:)]) { [delegate performSelector:@selector(doSomething:) withObject:filenames]; }这将调用控制器对象中的doSomething方法。
这里更新了示例项目代码。
Answering my own question.
It seems that subclassing the NSTableView (not the NSScrollView or the NSClipView) is the right way to go.
Including this method in the subclass :
- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender { return [self draggingEntered:sender]; }Solves the problem of prepareForDragOperation and performDragOperation not being called.
To allow you to call a method within a controller class, you make the delagate of your NSTextView to be the controller. In this case FileListController.
Then within performDragOperation in the NSTableView subclass you use something like :
NSPasteboard *pboard = [sender draggingPasteboard]; NSArray *filenames = [pboard propertyListForType:NSFilenamesPboardType]; id delegate = [self delegate]; if ([delegate respondsToSelector:@selector(doSomething:)]) { [delegate performSelector:@selector(doSomething:) withObject:filenames]; }This will call the doSomething method in the controller object.
Updated example project code here.
更多推荐
发布评论