【问题标题】:How to select items in NSOutlineView without NSTreeController?如何在没有 NSTreeController 的情况下选择 NSOutlineView 中的项目?
【发布时间】:2010-11-08 23:12:05
【问题描述】:

我使用NSOutlineView 没有 NSTreeController 并实现了我自己的数据源。选择项目的最佳方法是什么? NSOutlineView 已经支持 expandItem:collapseItem:。而且我缺少一个方便的方法,例如`selectItem:。我怎样才能以编程方式做到这一点?

谢谢。

【问题讨论】:

    标签: cocoa select nsoutlineview


    【解决方案1】:

    记得在找不到东西时查看超类。在这种情况下,您需要的方法之一来自 NSTableView,它是 NSOutlineView 的直接超类。

    解决方案是get the row index for the item using rowForItem:,如果不是-1(项目不可见/未找到),create an index set with it with [NSIndexSet indexSetWithIndex:] 并将该索引集传递给the selectRowIndexes:byExtendingSelection: method

    【讨论】:

    • 嗨彼得,谢谢你的回答。我已经知道方法 selectRowIndexes:byExtendingSelection:。问题是 NSOutlineView 正在使用 NSIndexPath 而不是 NSIndexSet。
    • 我在 NSOutlineView 文档中没有看到 NSIndexPath 的单个实例。也许您正在考虑您没有使用的 NSTreeController。此外,大纲视图表格视图,这意味着所有表格视图功能都应该在大纲视图中正常工作。
    • 是的,我明白了。遗憾的是,没有不依赖于我的数据源的内置解决方案。我必须在我的数据源中编写额外的代码,对吧?
    • 没有。这三个步骤是您选择特定项目所要做的全部。 (或项目,就此而言。)
    • 如果 rowForItem: 失败,我认为我至少需要数据源中的代码来扩展节点。
    【解决方案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: 方法。如果您将其与上述 Peter 关于使用 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 中的项目的代码 sn-p。

    sourceList 是一个常规的 PXSouceList 对象,我想选择大纲第一组中的第二项。

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

    如果您还不知道,如果您正在寻找 iTunes/邮件样式大纲,PXSourceList 是 NSOutlineView 的绝佳替代品。在这里拿起它: 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)
      }
      

      【讨论】:

      • 我不同意。扩展项是视图的一个特性,应该由 outlineView 处理;它与模型无关。您只是在复制 outlineView 无论如何都必须执行的代码。
      • 你有你如何做的例子吗?
      • 查看我在上面发布的答案 - 在没有索引计算的情况下,它或多或少地在同一个地方结束。
      【解决方案6】:

      (这仍然是 Google 上的最高搜索结果)

      斯威夫特 4.2:

      您需要确保先展开父级:

      if let parent = outlineView.parent(myItem){
              mapOutlineView.expandItem(parent)
      }
      
      
      let rowIndex = outlineView.row(forItem: myItem)
              guard rowIndex != -1 else {return}
              outlineView.selectRowIndexes(IndexSet(integer: rowIndex), byExtendingSelection: false)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-01-16
        • 1970-01-01
        • 2015-12-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-04-19
        相关资源
        最近更新 更多