перестановка строк таблицы путем перетаскивания в Lion - PullRequest
6 голосов
/ 31 декабря 2011

У меня проблемы с использованием новой функциональности Lion для перестановки строк в моем приложении. Я использую outlineView:pasteboardWriterForItem: для хранения индексов строк, чтобы я мог получить к ним доступ позже, когда я проверю / приму удаление. Я создаю новый NSPasteboardItem для возврата и пытаюсь сохранить номер строки следующим образом:

[pbItem setData: [NSKeyedArchiver archivedDataWithRootObject: [NSNumber numberWithInteger: [fTableView rowForItem: item]]]
                                                     forType: TABLE_VIEW_DATA_TYPE];

TABLE_VIEW_DATA_TYPE - пользовательская строка, которую я использую, чтобы различать мои пользовательские данные в перетаскиваемой монтажной панели. Я не использую его вне перетаскивания этих строк.

При попытке перетаскивания я получаю в консоли: 'TableViewDataType' is not a valid UTI string. Cannot set data for an invalid UTI.

Конечно, я мог бы использовать некоторые из встроенных UTI для монтажных панелей, но ни один из них не применяется (и их использование приводит к тому, что перетаскивание принимает перетаскивания, отличные от строк, что не должно). Есть ли что-то, чего я упускаю, например, способ определить пользовательский UTI только для перетаскивания (без превращения его в «настоящий» UTI, поскольку я не использую его вне внутреннего перетаскивания, поэтому он не должен быть публичным).

Спасибо за любую помощь!

Ответы [ 3 ]

7 голосов
/ 24 декабря 2013

У меня были аналогичные требования, за исключением того, что у меня была сетка объектов, которые я хотел переставить, перетаскивая выбранные объекты в новое место.Есть несколько способов сделать это, включая создание пользовательского объекта и реализацию протоколов NSPasteboardWriting и NSPasteboardReading (и протоколов NSCoding, если вы будете читать данные как NSPasteboardReadingAsKeyedArchive), но это кажется излишним дляперетаскивание объектов, которые остаются внутренними для приложения.

То, что я сделал, включает использование NSPasteboardItem в качестве оболочки с пользовательским типом UTI (он уже реализует протоколы NSPasteboardWriting и NSPasteboardReading).Сначала объявите пользовательский тип UTI:

#define kUTIMyCustomType @“com.mycompany.MyApp.MyCustomType”

Это необходимо определить в формате 'com.domain.MyApp', в противном случае вы получите ошибки в форме: «XXX недопустимая строка UTI.Невозможно установить данные для недопустимого UTI ». Apple упоминает об этом в своей документации.

Затем необходимо зарегистрировать этот пользовательский тип UTI в представлении, в котором будет происходить перетаскивание.Это может быть сделано во время выполнения и не требует никаких дополнений .plist.В метод init вашего представления добавьте следующее:

[self registerForDraggedTypes:[NSArray arrayWithObjects:(NSString *)kUTIMyCustomType, nil]];

Теперь убедитесь, что делегат установлен для этого представления, и объект делегата реализует требуемые методы протокола NSDraggingSource и NSDraggingDestination.Это позволит вам избежать нарушения шаблона проектирования MVC, позволяя назначенному объекту контроллера обрабатывать размещение данных на монтажном столе, что, вероятно, потребует запроса данных модели (т. Е. Индексов).

В частности, для размещения наперетаскивающий монтажный указатель индексы объектов, которые должны быть перемещены при перетаскивании, начинается как NSPasteboardItem оболочки ваших данных индекса:

- (void) draggingSession:(NSDraggingSession *)session willBeginAtPoint:(NSPoint)screenPoint
{
    NSPasteboard * pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
    [pboard clearContents];

    NSMutableArray * selectedIndexes = [NSMutableArray array];

    // Add NSString indexes for dragged items to pasteboard in NSPasteboardItem wrappers.
    for (MyModel * myModel in [self selectedObjects])
    {
        NSPasteboardItem * pasteboardItem = [[[NSPasteboardItem alloc] init] autorelease];
        [pasteboardItem setString:[NSString stringWithFormat:@"%@", [myModel index]]
                        forType:kUTIMyCustomType];
        [selectedIndexes addObject:pasteboardItem];
    }

    [pboard writeObjects:selectedIndexes];
}

А когда операция перетаскивания завершается, для чтения перетаскиваемого индекса NSPasteboardItem данные:

- (BOOL) performDragOperation:(id <NSDraggingInfo>)sender
{
    NSPasteboard * pasteboard = [sender draggingPasteboard];

    // Check for custom NSPasteboardItem's which wrap our custom object indexes.
    NSArray * classArray = [NSArray arrayWithObject:[NSPasteboardItem class]];
    NSArray * items = [pasteboard readObjectsForClasses:classArray options:[NSDictionary dictionary]];

    if (items == nil)
        return NO;

    // Convert array of NSPasteboardItem's with NSString index reps. to array of NSNumber indexes.
    NSMutableArray * indexes = [NSMutableArray array];
    for (NSPasteboardItem * item in items)
        [indexes addObject:[NSNumber numberWithInteger:[[item stringForType:kUTIMyCustomType] integerValue]]];

    //
    // Handle dragged indexes…
    //

    return YES;
}
6 голосов
/ 08 марта 2012

Другая техника, которую вы можете использовать, - это просто сохранить индексы объектов, которые вы перетаскиваете, в переменной экземпляра на стороне. Помещать все в монтажный картон не обязательно, если вы не принимаете предметы из другого приложения или наоборот.

  1. В awakeFromNib зарегистрируйтесь для NSStringPboardType.
  2. В… pasteboardWriterForRow вернуть [NSString string].
  3. В… draggingSession: willBegin… установите переменную вашего экземпляра для индексов, которые вы хотите отслеживать.
  4. В validateDrop вернуть NSDragOperationNone, если переменная вашего экземпляра равна nil или представление не ваше.
  5. В ... draggingSession: закончен ..., исключить переменную вашего экземпляра.

Надеюсь, это поможет ... Я использую технику для табличного представления, но она должна быть практически идентичной для контурного представления.

2 голосов
/ 31 декабря 2011

Вместо использования ванили NSPasteboardItem вы должны создать пользовательский объект, соответствующий протоколу NSPasteboardWriting.

В своем пользовательском объекте вы можете реализовать writableTypesForPasteboard:вернуть список пользовательских UTI, которые поддерживает ваш элемент монтажа.Затем вы реализуете pasteboardPropertyListForType:, чтобы возвращать plist-представление вашего объекта для соответствующего пользовательского UTI, когда об этом запрашивает монтажный картон.

Вы можете создать plist из произвольных данных, используя метод +propertyListWithData:options:format:error: из NSPropertyListSerialization.

Затем вы переопределите tableView:pasteboardWriterForRow: в вашем источнике данных табличного представления, чтобы вернуть экземпляр вашего пользовательского объекта.

...