【问题标题】:Implementing drag and drop in NSTableView在 NSTableView 中实现拖放
【发布时间】:2011-08-22 06:29:32
【问题描述】:

谁能帮我在 NSTableView 中实现拖放?我在下面使用了这段代码,但这些方法在执行期间没有被调用。

- (BOOL)tableView:(NSTableView *)tv writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard*)pboard
{
    // Copy the row numbers to the pasteboard.
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:rowIndexes];
    [pboard declareTypes:[NSArray arrayWithObject:@".gif"] owner:self];
    [pboard setData:data forType:@".gif"];
    return YES;
}

- (NSDragOperation)tableView:(NSTableView*)tv validateDrop:(id <NSDraggingInfo>)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)op
{
    // Add code here to validate the drop

    if (row > [ m_imageArray count])
        return NSDragOperationNone;

    if (nil == [info draggingSource]) // From other application
    {
        return NSDragOperationNone;
    }
    else if (self == [info draggingSource]) // From self
    {
        return NSDragOperationNone;
    }
    else // From other documents 
    {
        [tv setDropRow: row dropOperation: NSTableViewDropAbove];
        return NSDragOperationCopy;
    }

    NSLog(@"validate Drop");
    return NSDragOperationCopy;
}


- (BOOL)tableView:(NSTableView *)aTableView acceptDrop:(id <NSDraggingInfo>)info
              row:(NSInteger)row dropOperation:(NSTableViewDropOperation)operation
{
    NSPasteboard* pboard = [info draggingPasteboard];
    NSData* rowData = [pboard dataForType:@".gif"];
    NSIndexSet* rowIndexes = [NSKeyedUnarchiver unarchiveObjectWithData:rowData];
    NSInteger dragRow = [rowIndexes firstIndex];

    // Move the specified row to its new location...
}

【问题讨论】:

    标签: objective-c cocoa drag-and-drop nstableview


    【解决方案1】:

    这是一个例子

    #import "TableViewController.h"
    #import "Person.h"
    
    #define MyDataType @"MyDataType"
    
    @implementation TableViewController {
        NSMutableArray *list;
        NSInteger sourceIndex;
    }
    @synthesize tableView;
    
    -(void)awakeFromNib {
        [tableView registerForDraggedTypes:[NSArray arrayWithObjects:MyDataType, nil]];
        list = [[NSMutableArray alloc] init];
        Person *person = [[Person alloc] initWithName:@"Newton" age:64];
        [list addObject:person];
        person = [[Person alloc] initWithName:@"Archimedes" age:74];
        [list addObject:person];
        person = [[Person alloc] initWithName:@"Euler" age:44];
        [list addObject:person];
        person = [[Person alloc] initWithName:@"Poincare" age:24];
        [list addObject:person];
        person = [[Person alloc] initWithName:@"Gauss" age:34];
        [list addObject:person];
    }
    
    -(void)reArrange:(NSMutableArray *)array sourceNum:(NSInteger)sourceNum destNum:(NSInteger)destNum {
        Person *person = list[sourceNum];
        [list insertObject:person atIndex:destNum];
    
        if (sourceNum < destNum) {
            [list removeObjectAtIndex:sourceNum];
        } else {
            [list removeObjectAtIndex:sourceNum+1];
        }
    
        [tableView reloadData];
    }
    
    
    #pragma mark - Table
    
    // how many rows are there in the table?
    -(NSInteger)numberOfRowsInTableView:(NSTableView *)tv {
        return list.count;
    }
    
    // What object should I show in a particular cell?
    -(id)tableView:(NSTableView *)tv objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
        Person *person = list[row];
        NSString *identifier = [tableColumn identifier];
        return [person valueForKey:identifier];
    }
    
    // Should I accept the drag with the rows specified by rowIndexes? If YES then place the data on the provided paste board.
    - (BOOL)tableView:(NSTableView *)tv writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pboard {
        NSData *data = [NSKeyedArchiver archivedDataWithRootObject:rowIndexes];
        [pboard declareTypes:[NSArray arrayWithObject:MyDataType] owner:self];
        [pboard setData:data forType:MyDataType];
        sourceIndex = [rowIndexes firstIndex];
        return YES;
    }
    
    // What kind of drag operation should I perform?
    - (NSDragOperation)tableView:(NSTableView*)tv validateDrop:(id )info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)op {
        return op == NSTableViewDropAbove; // Specifies that the drop should occur above the specified row.
    }
    
    // The mouse button was released over a row in the table view, should I accept the drop?
    - (BOOL)tableView:(NSTableView*)tv acceptDrop:(id )info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)op {
        [self reArrange:list sourceNum:sourceIndex destNum:row]; // let the source array reflect the change
        return YES;
    }
    
    @end
    

    【讨论】:

    • 这是一个更全面的回复,感谢您的宝贵时间。
    【解决方案2】:

    您需要为您的表格视图声明一个自定义拖动类型,然后使用您的自定义类型调用registerForDraggedTypes:。否则,正如您所注意到的,这些方法都不会被调用。

    【讨论】:

    • 您好,感谢您的建议。但我不知道如何声明自定义拖动类型
    【解决方案3】:

    使用核心数据拖放 NSTableview

    1. 为拖放注册表格视图对象:-

      [tblCategory registerForDraggedTypes:[NSArray arrayWithObject:@"public.text"]];
      

    拖放委托方法:-

     - (id <NSPasteboardWriting>)tableView:(NSTableView *)tableView pasteboardWriterForRow:(NSInteger)row
     {
    
     Category *category = (Category *)[self.arrCategoryList objectAtIndex:row];
     NSString *identifier = category.categoryname;
    
     NSPasteboardItem *pboardItem = [[NSPasteboardItem alloc] init];
     [pboardItem setString:identifier forType: @"public.text"];
     return pboardItem;
     }
    
     - (NSDragOperation)tableView:(NSTableView *)tableView validateDrop:(id <NSDraggingInfo>)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)dropOperation
    {
    
    
    if(dropOperation == NSTableViewDropOn)
    {
    NSPasteboard *p = [info draggingPasteboard];
    NSString *title = [p stringForType:@"public.text"];
    Category* category ;
    NSInteger srcIndex;
    for (srcIndex = 0; srcIndex < [_arrCategoryList count]; srcIndex++)
    {
      category = [_arrCategoryList objectAtIndex:srcIndex];
    if ([category.categoryname isEqualToString:title])
    {
            break;
    }
        category = nil;
    }
    if(!category)
    {
         // Not found
         return NO;
     }
    
     [_arrCategoryList removeObjectAtIndex:srcIndex];
     [_arrCategoryList insertObject:category atIndex:row];
     [tblCategory reloadData];
     return NSDragOperationMove;
    }
      return NSDragOperationNone;
    }
    
     - (BOOL)tableView:(NSTableView *)tableView acceptDrop:(id <NSDraggingInfo>)info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)dropOperation
     {
       return YES;
    }
    

    【讨论】:

      【解决方案4】:

      当我忘记将dataSource连接到IB中的NSTabeView时,我通常会观察到这种错误,即实现NSTableViewDataSourcetableView:writeRowsWithIndexes:toPasteboard:方法的类。

      【讨论】:

        【解决方案5】:

        您可以为 NSMutableArray 或 NSMutableDictionary 或任何其他对象注册 draggedTypes。以下代码 sn-p 用于 NSMutableArray。

        [tableView registerForDraggedTypes:[NSArray arrayWithObject:@"NSMutableArray"] ];

        【讨论】:

          【解决方案6】:

          你需要在awakFromnib中声明一个registerForDraggedTypes方法

          像这样。

          [table_view registerForDraggedTypes:[NSArray arrayWithObjects:BasicTableViewDragAndDropDataType, nil]];
          

          【讨论】:

            【解决方案7】:

            我不得不推荐这篇出色的 Red Sweater 博文

            http://www.red-sweater.com/blog/274/a-moveable-beast

            它提供了一个 NSArrayController 子类,它可以对表格项进行拖放重新排序,如果你想支持用你的对象拖到表格视图之外,我们刚刚写了一个简洁的补充那个班级:

            http://www.rwe-uk.com/blog/comments/nstableview_drag_and_drop_with_bindings_and_nsarraycontroller

            它建立在原始帖子的基础上

            【讨论】:

            • 链接损坏“站点错误:无法加载站点首选项;未找到首选项”
            猜你喜欢
            • 1970-01-01
            • 2010-10-13
            • 2012-05-05
            • 1970-01-01
            • 2012-02-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多