以编程方式将 NSTableView 绑定到 NSArrayController
Binding NSTableView to NSArrayController programmatically
我正在尝试在代码中将 NSTextView
绑定到 NSArrayController
,并且已经回答了关于该主题的几个问题:here, here, and 。我正在使用 Xcode 9.2 和 Swift 4.
构建一个 MacOS 应用程序
我有一个带有 2 个按钮的 SegmentedControl
:一个用于添加新对象,另一个用于删除。当我尝试将 a NSTextField
绑定到添加到数组的新创建对象时,我崩溃了。
我的 VeiwController
代码:
private enum Columns {
static let name = NSUserInterfaceItemIdentifier("NameColumn")
static let age = NSUserInterfaceItemIdentifier("AgeColumn")
}
let arrayController: NSArrayController
let table: NSTableView
let buttons: NSSegmentedControl
// MARK: —Initialisation—
required init() {
super.init(nibName: nil, bundle: nil)
/// Code to create arrayController, table, and buttons
///...
/// Bindings.
table.bind(.content,
to: self.arrayController,
withKeyPath: "arrangedObjects",
options: nil)
/// Delegates
table.delegate = self
buttons.target = self
buttons.action = #selector(splitButtonClicked)
}
函数从 arrayController
到 add/remove 个对象。 Person
是一个简单的 class,具有 2 个属性(Name
和 Age
):
@objc func splitButtonClicked() {
switch buttons.selectedSegment {
case 0:
let person = Person()
person.name = "Alfred"
person.age = 21
arrayController.addObject(person)
case 1:
arrayController.removeObject(arrayController.selectedObjects)
default:
print("Switch case error")
}
}
创建新 table 行 returns 新 NSTextField
的代码,但是当我尝试绑定文本字段时我崩溃了,我不确定为什么:
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
guard let column = tableColumn else { return nil }
let t = NSTextField(frame: NSRect(x: 0, y: 0, width: column.width, height: table.rowHeight))
if column.identifier == Columns.name {
/// Crashing on this line.
t.bind(.value, to: t, withKeyPath: "objectValue.name", options: nil)
} else if column.identifier == Columns.age {
t.bind(.value, to: t, withKeyPath: "objectValue.age", options: nil)
}
return t
}
这两行:
let t = NSTextField(...)
t.bind(.value, to: t, withKeyPath: "objectValue.name", options: nil)
您在不存在的键路径上将文本字段绑定到自身。如果展开 table 视图的视图层次结构,它是这样的:
Table View > Column > Cell View > Text Field
您需要提供的是 Cell View,其中嵌套了文本字段。
fileprivate extension NSUserInterfaceItemIdentifier {
static let cellView = NSUserInterfaceItemIdentifier("CellView")
static let name = NSUserInterfaceItemIdentifier("NameColumn")
static let age = NSUserInterfaceItemIdentifier("AgeColumn")
}
extension ViewController: NSTableViewDelegate, NSTableViewDataSource {
private func makeCell(frame: CGRect) -> NSTableCellView {
// Reuse an existing cell if possible
if let existingCell = table.makeView(withIdentifier: .cellView, owner: nil) as? NSTableCellView {
return existingCell
}
// Make a new cell
let textField = NSTextField(frame: frame)
textField.drawsBackground = false
textField.isBordered = false
let cell = NSTableCellView(frame: frame)
cell.identifier = .cellView
cell.textField = textField
cell.addSubview(textField)
return cell
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
guard let column = tableColumn else { return nil }
let cell = makeCell(frame: NSRect(x: 0, y: 0, width: column.width, height: table.rowHeight))
// Varying the binding based on what column is being requested
switch column.identifier {
case .name:
cell.textField?.bind(.value, to: cell, withKeyPath: "objectValue.name", options: nil)
case .age:
cell.textField?.bind(.value, to: cell, withKeyPath: "objectValue.age", options: nil)
default:
print("Unrecognized column '\(column.identifier)'")
}
return cell
}
}
我正在尝试在代码中将 NSTextView
绑定到 NSArrayController
,并且已经回答了关于该主题的几个问题:here, here, and
我有一个带有 2 个按钮的 SegmentedControl
:一个用于添加新对象,另一个用于删除。当我尝试将 a NSTextField
绑定到添加到数组的新创建对象时,我崩溃了。
我的 VeiwController
代码:
private enum Columns {
static let name = NSUserInterfaceItemIdentifier("NameColumn")
static let age = NSUserInterfaceItemIdentifier("AgeColumn")
}
let arrayController: NSArrayController
let table: NSTableView
let buttons: NSSegmentedControl
// MARK: —Initialisation—
required init() {
super.init(nibName: nil, bundle: nil)
/// Code to create arrayController, table, and buttons
///...
/// Bindings.
table.bind(.content,
to: self.arrayController,
withKeyPath: "arrangedObjects",
options: nil)
/// Delegates
table.delegate = self
buttons.target = self
buttons.action = #selector(splitButtonClicked)
}
函数从 arrayController
到 add/remove 个对象。 Person
是一个简单的 class,具有 2 个属性(Name
和 Age
):
@objc func splitButtonClicked() {
switch buttons.selectedSegment {
case 0:
let person = Person()
person.name = "Alfred"
person.age = 21
arrayController.addObject(person)
case 1:
arrayController.removeObject(arrayController.selectedObjects)
default:
print("Switch case error")
}
}
创建新 table 行 returns 新 NSTextField
的代码,但是当我尝试绑定文本字段时我崩溃了,我不确定为什么:
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
guard let column = tableColumn else { return nil }
let t = NSTextField(frame: NSRect(x: 0, y: 0, width: column.width, height: table.rowHeight))
if column.identifier == Columns.name {
/// Crashing on this line.
t.bind(.value, to: t, withKeyPath: "objectValue.name", options: nil)
} else if column.identifier == Columns.age {
t.bind(.value, to: t, withKeyPath: "objectValue.age", options: nil)
}
return t
}
这两行:
let t = NSTextField(...)
t.bind(.value, to: t, withKeyPath: "objectValue.name", options: nil)
您在不存在的键路径上将文本字段绑定到自身。如果展开 table 视图的视图层次结构,它是这样的:
Table View > Column > Cell View > Text Field
您需要提供的是 Cell View,其中嵌套了文本字段。
fileprivate extension NSUserInterfaceItemIdentifier {
static let cellView = NSUserInterfaceItemIdentifier("CellView")
static let name = NSUserInterfaceItemIdentifier("NameColumn")
static let age = NSUserInterfaceItemIdentifier("AgeColumn")
}
extension ViewController: NSTableViewDelegate, NSTableViewDataSource {
private func makeCell(frame: CGRect) -> NSTableCellView {
// Reuse an existing cell if possible
if let existingCell = table.makeView(withIdentifier: .cellView, owner: nil) as? NSTableCellView {
return existingCell
}
// Make a new cell
let textField = NSTextField(frame: frame)
textField.drawsBackground = false
textField.isBordered = false
let cell = NSTableCellView(frame: frame)
cell.identifier = .cellView
cell.textField = textField
cell.addSubview(textField)
return cell
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
guard let column = tableColumn else { return nil }
let cell = makeCell(frame: NSRect(x: 0, y: 0, width: column.width, height: table.rowHeight))
// Varying the binding based on what column is being requested
switch column.identifier {
case .name:
cell.textField?.bind(.value, to: cell, withKeyPath: "objectValue.name", options: nil)
case .age:
cell.textField?.bind(.value, to: cell, withKeyPath: "objectValue.age", options: nil)
default:
print("Unrecognized column '\(column.identifier)'")
}
return cell
}
}