【问题标题】:Using type select on only one column with NSTableView in Swift在 Swift 中仅使用 NSTableView 在一列上使用类型选择
【发布时间】:2018-04-30 00:43:01
【问题描述】:

我正在使用 XCode 9.3,Swift 为 MacOS 开发应用程序。

我创建了一个当前有两列的表。我想使用只作用于一列的类型选择,这样当用户键入前几个字母时,它只在第一列中选​​择,而不是在第二列中选择。

Apple 文档在 Objective-C 中有一个示例:https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/TableView/RowSelection/RowSelection.html#//apple_ref/doc/uid/10000026i-CH6-SW1 但我似乎无法将其翻译成 Swift。我在下面包含了表格代码。任何帮助都将不胜感激。

extension ViewController: NSTableViewDataSource {
  func numberOfRows(in tableView: NSTableView) -> Int {
    return directoryItems?.count ?? 0
  }

  // Sorting.
  func tableView(_ tableView: NSTableView, sortDescriptorsDidChange oldDescriptors: [NSSortDescriptor]) {
    guard let sortDescriptor = tableView.sortDescriptors.first else {
      return
    }

    if let order = Directory.FileOrder(rawValue: sortDescriptor.key!) {
      sortOrder = order
      sortAscending = sortDescriptor.ascending
      reloadFileList()
    }
  }

}

extension ViewController: NSTableViewDelegate {

  fileprivate enum CellIdentifiers {
    static let NameCell = "NameCellID"
    static let TimeCell = "TimeCellID"
    static let SizeCell = "SizeCellID"
  }

  func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {

    var image: NSImage?
    var text: String = ""
    var cellIdentifier: String = ""

    let dateFormatter = DateFormatter()
    dateFormatter.dateStyle = .long
    dateFormatter.timeStyle = .long

    guard let item = directoryItems?[row] else {
      return nil
    }

    if tableColumn == tableView.tableColumns[0] {
      image = item.icon
      text = item.name
      cellIdentifier = CellIdentifiers.NameCell

    } else if tableColumn == tableView.tableColumns[1] {
      let asset = AVAsset(url: item.url as URL)
      let audioTime = asset.duration
      text = audioTime.durationText
      cellIdentifier = CellIdentifiers.TimeCell

    } else if tableColumn == tableView.tableColumns[2] {
      text = item.isFolder ? "--" : sizeFormatter.string(fromByteCount: item.size)
      cellIdentifier = CellIdentifiers.SizeCell
    }

    if let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: cellIdentifier), owner: nil) as? NSTableCellView {
      cell.textField?.stringValue = text
      cell.imageView?.image = image ?? nil
      return cell
    }

    return nil
  }

}

【问题讨论】:

  • 到目前为止您尝试了哪些方法,结果与您想要的有何不同?
  • 我已经尝试过:func tableView(_ tableView: NSTableView,shouldTypeSelectFor event: NSEvent,withCurrentSearch searchString: String?) -> Bool { return true } 如果我将返回更改为 false,则类型选择在任何地方都不起作用。我尝试添加 if 语句,但似乎无法提取列或单元格的名称。他们都回来“零”。我不完全确定我是否在正确的地方尝试了该功能,或者它是否是正确的开始。我可以用它来捕获可选的搜索字符串,但仅此而已。
  • 您能否发布您尝试获取列名的shouldTypeSelectFor:etc:etc: 方法的内容?我可能可以帮助解决这个问题,但我需要看看你到目前为止所做的尝试,看看出了什么问题。
  • 我试过把它放在 NSTableViewDelegate; func tableView(_ tableView: NSTableView,shouldTypeSelectFor event: NSEvent,withCurrentSearch searchString: String?) -> Bool { if tableView.cell?.title == "NameCellID" { print(String(describing: tableView.cell?.title)) return true } else { print(String(describing: tableView.cell?.title)) return false } } tableView.cell?.title 只是显示为 nil。我希望我对此有更好的理解,但我就是没有。

标签: swift macos nstableview


【解决方案1】:

你的问题是双重的:

首先,您需要为每个表格列设置一个标识符。您可以通过选择 Interface Builder 中的列、转到 Identity Inspector 并将其设置为某个字符串值来执行此操作:

完成此操作后,创建一些静态属性来引用这些标识符(这严格不是必需的,因为您当然可以只使用rawValue 进行纯字符串比较Objective-C 的方式,但新的 Swift 4 标识符是类型安全的,因此是首选)。这样做:

extension ViewController: NSTableViewDelegate {
    private struct TableColumns {
        static let foo = NSUserInterfaceItemIdentifier("Foo")
        static let bar = NSUserInterfaceItemIdentifier("Bar")
    }

    ...

}

现在,您可以使用这些标识符来引用您的列,使用 tableColumn(withIdentifier:)(或 column(withIdentifier:),如果您只需要列号)。我建议在您引用它们的任何地方都这样做,包括在您的 tableView(:viewFor:row:) 方法中,因为您现在使用 tableView.tableColumns[0] 等的方式取决于列的顺序,如果用户重新排序它们,它可能会导致意外行为。使用标识符将确保您始终查看您认为正在查看的列。

无论如何,一旦您设置了标识符,您就可以解决第二个问题:您使用了错误的委托方法。使用tableView(:typeSelectStringFor:row:),而不是tableView(:shouldTypeSelectFor:searchString:),它用于在事件级别捕获这些东西(即,用户只是按下了一个键。我应该调用类型选择系统吗?)。此方法允许您为表中的每个行/列组合返回给定类型选择机制的字符串。对于您希望类型选择忽略的那些,只需返回nil;否则,返回您希望输入以选择该特定行的字符串。所以,类似:

func tableView(_ tableView: NSTableView, typeSelectStringFor tableColumn: NSTableColumn?, row: Int) -> String? {
    if tableColumn?.identifier == TableColumns.foo {
        return directoryItems?[row].name
    } else {
        return nil
    }
}

【讨论】:

  • 是的!那成功了。非常感谢。关于表格,我还有很多东西要学。你的解释是如此清晰和透彻。我真的很感激!
  • @RickshawBoy 很高兴。将来,请务必在问题中包含您已经尝试过的代码。它使您更容易弄清楚您要做什么以及如何提供帮助。
猜你喜欢
  • 1970-01-01
  • 2018-08-23
  • 2014-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多