软体中需要实现拖拽选择文件, 并存储选择历史记录的功能, 所以选择使用NSComboBox作为控件, 设置其为不可编辑, 实现拖拽效果如下
要想实现拖拽的功能, MacOS Appkit给我们提供了几个基础类:
Drag 相关类和协议位于 AppKit 中
NSDraggingImageComponent
NSDraggingItem
NSDraggingSession
protocols
// Protocols:
NSDraggingInfo
NSDraggingDestination
NSDraggingSource
NSSpringLoadingDestination
可拖拽的对象,需要遵守 NSDraggingSource 协议;
可作为拖拽目标的对象,遵守 NSDraggingDestination 协议。
AppKit 隐藏了鼠标追踪和展示拖拽视图的所有细节。
NSWindow 和 NSView 对象可以成为drags 的资源地和目的地。
经查询发现, Appkit中不同的控件基本上都继承自这两个协议, 要想实现拖拽功能, 我们在自定义的class中实现不同的协议即可:
比如:
NSTextView继承了协议NSDraggingSource
#import <AppKit/NSDragging.h>
@interface NSTextView : NSText <NSColorChanging, NSMenuItemValidation,
NSUserInterfaceValidations, NSTextInputClient, NSTextLayoutOrientationProvider,
NSDraggingSource, NSStandardKeyBindingResponding, NSTextInput,
NSAccessibilityNavigableStaticText>
NSView继承了协议NSDraggingDestination
@interface NSView : NSResponder <NSAnimatablePropertyContainer,
NSUserInterfaceItemIdentification, NSDraggingDestination, NSAppearanceCustomization,
NSAccessibilityElement, NSAccessibility>
基本上所有的控件都是继承自NSView的, 所以可以说所有的控件都可实现拖拽功能, 只需自定义并实现NSDraggingDestination中的方法
我自定义了ComboBox实现如下:
#import "DragComboBox.h"
@implementation DragComboBox
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
// Drawing code here.
}
-(void)awakeFromNib{
self.dbfile=[[[NSBundle mainBundle]resourcePath]stringByAppendingPathComponent:@"history.plist"];
if ([[NSFileManager defaultManager]fileExistsAtPath:self.dbfile]){
self.db=[NSMutableDictionary dictionaryWithContentsOfFile:self.dbfile];
NSArray *items = [self.db objectForKey:@"items"];
if (items && items.count>0){
[self removeAllItems];
for (int i=0; i<items.count;i++){
[self insertItemWithObjectValue:items[i] atIndex:i];
}
}
}
[self registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
self.delegate = self;
}
-(void)saveData{
if (!self.db){
self.db=[NSMutableDictionary dictionary];
}
if (![self.stringValue isEqualToString:@""] && ![self.objectValues containsObject:self.stringValue]){
[self insertItemWithObjectValue:self.stringValue atIndex:0];
// 根据实际使用情况, 最多保存30条记录就足够了
if(self.numberOfItems>31){
[self removeItemAtIndex:30];
}
}
[self.db setObject:self.objectValues forKey:@"items"];
[self.db setObject:self.stringValue forKey:@"LastSelected"];
[self.db writeToFile:self.dbfile atomically:YES];
}
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
{
if ([[[sender draggingPasteboard] types] containsObject:NSFilenamesPboardType])
{
return NSDragOperationCopy;
}
return NSDragOperationNone;
}
- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
{
return [self draggingEntered:sender];
}
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
NSPasteboard *pboard;
pboard = [sender draggingPasteboard];
if ([[pboard types] containsObject:NSFilenamesPboardType]){
NSArray *filenames = [pboard propertyListForType:NSFilenamesPboardType];
NSString *fn = [filenames firstObject];
if (fn && ([fn hasSuffix:@".hex"]||[fn hasSuffix:@".bin"])) {
self.stringValue=fn;
}else{
self.stringValue=@"";
}
return YES;
}
return NO;
}
// 最后一项是Clear, 当选择clear时, 清除所有的history记录
-(void)comboBoxSelectionDidChange:(NSNotification *)notification{
NSString *selected = self.objectValueOfSelectedItem;
if ([selected isEqualToString:@"Clear"]){
[self removeAllItems];
[self addItemWithObjectValue:@"Clear"];
[self setStringValue:@""];
}
}
macOS开发 - 文件拖放 DragDropView 的 'NSFilenamesPboardType' is deprecated