从Finder拖放到NSTableView怪异(Drag and Drop from the Finder to a NSTableView weirdness)

编程入门 行业动态 更新时间:2024-10-19 00:31:27
从Finder拖放到NSTableView怪异(Drag and Drop from the Finder to a NSTableView weirdness)

我试图了解如何最好地将文件从Finder拖放到NSTableView,随后将列出这些文件。

我已经建立了一个小测试应用程序作为试验场。

目前我有一个带有FileListController NSTableView作为它的数据。 它基本上是File对象的NSMutableArray。

我正在尝试找出最佳/正确的方法来实现NSTableView的拖放代码。

我的第一种方法是子类化NSTableView并实现所需的方法:

TableViewDropper.h

#import <Cocoa/Cocoa.h> @interface TableViewDropper : NSTableView @end

TableViewDropper.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]; } } @end

draggingEntered和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 @end

TableViewDropper.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]; } } @end

The 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.

更多推荐

本文发布于:2023-08-07 02:08:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1458485.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:怪异   拖放   NSTableView   Finder   Drop

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!