题
我想根据要显示的数据动态隐藏/显示 NSTableView 中的一些列 - 基本上,如果列为空,我希望隐藏该列。我当前正在使用控制器类作为表的委托来填充表。
有任何想法吗?我看到我可以在 Interface Builder 中设置隐藏的列,但是似乎没有一个好时机来浏览这些列并检查它们是否为空,因为似乎没有一种方法可以在填充表中的所有数据之前/之后调用。
解决方案
NSTable 只是绘制表格的类。正如您自己所说,您有一些类作为委托给表,并且该类向表提供要显示的数据。如果您将表数据存储为委托类中的 NSArray,那么应该很容易找出一列是否为空,不是吗?NSArray 通过委托方法询问您的类有多少列,因此当您被问到时,为什么不查找您有数据的多少列并报告该数字,而不是您内部存储的实际列数,然后在被要求时报告该数字提供(列,行)的数据,只需跳过空列。
其他提示
在 Mac OS X v10.5 及更高版本中,有 setHidden:
选择器 对于 NSTableColumn。
这允许使用标识符动态隐藏/显示列:
NSInteger colIdx;
NSTableColumn* col;
colIdx = [myTable columnWithIdentifier:@"columnIdent"];
col = [myTable.tableColumns objectAtIndex:colIdx];
[col setHidden:YES];
我已经使用绑定完成了此操作,但以编程方式设置它们,而不是通过 Interface Builder。
这个伪片段应该告诉你它的要点:
NSTableColumn *aColumn = [[NSTableColumn alloc] initWithIdentifier:attr];
[aColumn setWidth:DEFAULTCOLWIDTH];
[aColumn setMinWidth:MINCOLWIDTH];
[[aColumn headerCell] setStringValue:columnLabel];
[aColumn bind:@"value"
toObject:arrayController
withKeyPath:keyPath
options:nil];
[tableView addTableColumn:aColumn];
[aColumn release];
当然,您也可以添加格式化程序和所有这些东西。
它在 Interface Builder 中不起作用。然而它以编程方式工作。以下是我如何将带有标识符“Status”的 NSTableViewColumn 绑定到 NSUserDefaults 中的键:
迅速:
tableView.tableColumnWithIdentifier("Status")?.bind("hidden", toObject: NSUserDefaults.standardUserDefaults(), withKeyPath: "TableColumnStatus", options: nil)
Objective-C:
[[self.tableView tableColumnWithIdentifier:@"Status"] bind:@"hidden" toObject:[NSUserDefaults standardUserDefaults] withKeyPath:@"TableColumnStatus" options:nil];
我目前没有完整的答案,但请查看 Bindings。通常可以使用 Cocoa Bindings 做各种事情。
NSTableColumn 没有 Visibility 绑定,但您可以将宽度设置为 0。
然后,您可以将其绑定到 Null Placeholder,并将该值设置为 0 - 但不要忘记将其他占位符设置为合理的值。
(正如我所说,这只是一个开始,可能需要一些调整)。
不可能一次性填充所有数据。NSTableView 不存储数据,它动态地从其数据源(或绑定到对象,如果您使用绑定)请求数据。它只是使用从数据源获取的数据进行绘制,然后放弃它。例如,您不应该看到该表要求提供任何不可见的数据。
听起来您正在使用数据源?当数据更改时,您有责任在表上调用 -reloadData,这有点用词不当。它更像是“使一切无效”。
也就是说,您应该已经知道数据何时发生变化。您可以在此时计算应隐藏哪些列。
@amrox - 如果我正确理解你的建议,你是说我应该将一个值绑定到表中 NSTableColumns 的隐藏属性?这似乎可行,但我不认为 NSTableColumn 有隐藏属性,因为 isHidden 和 setHidden 消息控制列的可见性 - 这告诉我这不是一个属性,除非我错过了一些东西(这是很有可能的)。
我想发布我的解决方案,使用 Cocoa 绑定和实际的 Swift 4 更新 isHidden
标记而不触及列宽(因为您可能需要随后恢复原始值......)。假设我们有一个复选框来切换某些列的可见性(或者您始终可以切换 hideColumnsFlag
以下示例中的变量以您喜欢的任何其他方式):
class ViewController: NSViewController {
// define the boolean binding variable to hide the columns and use its name as keypath
@objc dynamic var hideColumnsFlag = true
// Referring the column(s)
// Method 1: creating IBOutlet(s) for the column(s): just ctrl-drag each column here to add it
@IBOutlet weak var hideableTableColumn: NSTableColumn!
// add as many column outlets as you need...
// or, if you prefer working with columns' string keypaths
// Method 2: use just the table view IBOutlet and its column identifiers (you **must** anyway set the latter identifiers manually via IB for each column)
@IBOutlet weak var theTableView: NSTableView! // this line could be actually removed if using the first method on this example, but in a real case, you will probably need it anyway.
// MARK: View Controller Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
// Method 1
// referring the columns by using the outlets as such:
hideableTableColumn.bind(.hidden, to: self, withKeyPath: "hideColumnsFlag", options: nil)
// repeat for each column outlet.
// Method 2
// or if you need/prefer to use the column identifiers strings then:
// theTableView.tableColumn(withIdentifier: .init("columnName"))?.bind(.hidden, to: self, withKeyPath: "hideColumnsFlag", options: nil)
// repeat for each column identifier you have set.
// obviously use just one method by commenting/uncommenting one or the other.
}
// MARK: Actions
// this is the checkBox action method, just toggling the boolean variable bound to the columns in the viewDidLoad method.
@IBAction func hideColumnsCheckboxAction(_ sender: NSButton) {
hideColumnsFlag = sender.state == .on
}
}
正如您可能已经注意到的,目前还没有办法绑定 Hidden
Interface Builder 中的标记与 XCode10 相同:你可以看到 Enabled
或者 Editable
绑定,但只有以编程方式您才能访问 isHidden
列的标志,正如 Swift 中所称的那样。
如注释中所述,第二种方法依赖于列标识符,您必须在选择相关列后通过 Interface Builder 在 Identity 字段上手动设置,或者如果您有列名称数组,则可以枚举表列并分配标识符以及绑定,而不是重复类似的代码行。