Как выбрать элементы в NSOutlineView без NSTreeController?

Я использую NSOutlineView без NSTreeController и внедрил свой собственный источник данных. Каков наилучший способ выбора элемента? NSOutlineView поддержка уже expandItem: и collapseItem:. И у меня отсутствует удобный метод, например `selectItem:. Как я могу сделать это программно?

Спасибо.

Ответ 1

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

Решение заключается в получить индекс строки для элемента с помощью rowForItem:, а если это не -1 (элемент не отображается /not found), создать с ним индекс с [NSIndexSet indexSetWithIndex:] и передать этот индекс, установленный в метод selectRowIndexes:byExtendingSelection:.

Ответ 2

Вот как я, наконец, закончил. Предложения и исправления всегда приветствуются.

@implementation NSOutlineView (Additions)

- (void)expandParentsOfItem:(id)item {
    while (item != nil) {
        id parent = [self parentForItem: item];
        if (![self isExpandable: parent])
            break;
        if (![self isItemExpanded: parent])
            [self expandItem: parent];
        item = parent;
    }
}

- (void)selectItem:(id)item {
    NSInteger itemIndex = [self rowForItem:item];
    if (itemIndex < 0) {
        [self expandParentsOfItem: item];
        itemIndex = [self rowForItem:item];
        if (itemIndex < 0)
            return;
    }

    [self selectRowIndexes: [NSIndexSet indexSetWithIndex: itemIndex] byExtendingSelection: NO];
}
@end

Ответ 3

Нет, нет метода selectItem:, но существует метод rowForItem:. Если вы соедините это с советом Питера об использовании selectRowIndexes:byExtendingSelection: выше, вы должны иметь всю необходимую информацию.

Если вы действительно хотели иметь метод для выбора элемента, который я бы рекомендовал вызывать setSelectedItem: для согласования, вы можете написать что-то вроде этого в категории на NSOutlineView

- (void)setSelectedItem:(id)item {
    NSInteger itemIndex = [self rowForItem:item];
    if (itemIndex < 0) {
        // You need to decide what happens if the item doesn't exist
        return;
    }

    [self selectRowIndexes:[NSIndexSet indexSetWithIndex:itemIndex] byExtendingSelection:NO];
}

Я не знаю, действительно ли этот код работает; Я просто бросил его, чтобы проиллюстрировать концепцию.

Ответ 4

Вот фрагмент кода, который я использовал для программного выбора элемента в PXSourceList.

sourceList - это обычный объект PXSouceList, и мне нужно выбрать второй элемент в первой группе контура.

    NSInteger itemRow = [sourceList rowForItem:[[(SourceListItem *)[sourceListItems objectAtIndex:0] children] objectAtIndex:1]];
    [sourceList selectRowIndexes:[NSIndexSet indexSetWithIndex:itemRow] byExtendingSelection:YES];

Если вы еще не знаете, PXSourceList - отличная замена NSOutlineView, если вы ищете контуры стиля itunes/mail. Возьмите его здесь: PxSourceList

Ответ 5

Это старый вопрос, но ситуация все та же. Поскольку был запрос на быструю версию, здесь мой взять. Я не нашел приемлемый ответ для меня, так как я думаю, что вы должны напрямую взаимодействовать с вашим классом источника данных, а не расширять NSOutlineView. Досадно, что контур не найдет строки, если они не развернуты, поэтому проще использовать ваш источник данных. В моем случае я обнаружил, что вам нужно расширить родительский элемент ваших элементов в обратном порядке, чтобы вы начали с верхнего уровня и продвигались к фактическому элементу, который пытаетесь расширить. Я чувствую, что это должно быть встроено, но если я что-то пропустил - это не так.

В этом примере FileItem - это мой класс элементов коллекции источника данных. Он содержит свойство parent, которое должно быть допустимым, если оно является частью отображаемой иерархии.

func selectItem(_ item: FileItem, byExtendingSelection: Bool = false) {
    guard let outlineView = outlineView else { return }

    var itemIndex: Int = outlineView.row(forItem: item)

    if itemIndex < 0 {
        var parent: FileItem? = item

        var parents = [FileItem?]()
        while parent != nil {
            parents.append(parent)
            parent = parent?.parent
        }

        let reversedTree = parents.compactMap({$0}).reversed()

        for level in reversedTree {
            outlineView.expandItem(level, expandChildren: false)
        }

        itemIndex = outlineView.row(forItem: item)
        if itemIndex < 0 {
            print("Didn't find", item)
            return
        }
    }

    print("Expanding row", itemIndex)

    outlineView.selectRowIndexes(IndexSet(integer: itemIndex), byExtendingSelection: byExtendingSelection)
    outlineView.scrollRowToVisible(itemIndex)
}