【问题标题】:Dynamically hiding columns in a NSTableView在 NSTableView 中动态隐藏列
【发布时间】:2010-09-09 06:56:35
【问题描述】:

我想根据要显示的数据动态隐藏/显示 NSTableView 中的某些列 - 基本上,如果一列是空的,我希望该列被隐藏。我目前正在使用控制器类作为表的委托填充表。

有什么想法吗?我看到我可以在 Interface Builder 中设置隐藏的列,但是似乎不是检查这些列并检查它们是否为空的好时机,因为似乎没有一种方法是在填充表中的所有数据之前/之后调用。

【问题讨论】:

    标签: cocoa macos


    【解决方案1】:

    在 Mac OS X v10.5 及更高版本中,NSTableColumn 有 setHidden: selector

    这允许使用标识符动态隐藏/显示列:

    NSInteger colIdx;
    NSTableColumn* col;
    
    colIdx = [myTable columnWithIdentifier:@"columnIdent"];
    col = [myTable.tableColumns objectAtIndex:colIdx];
    [col setHidden:YES];
    

    【讨论】:

    • NSTableColumn *column = [tableView.tableColumns objectAtIndex:2]; [列集隐藏:是];如果您知道确切的索引,它也可以用于隐藏列。
    【解决方案2】:

    我已经通过绑定完成了这项工作,但以编程方式而不是通过 Interface Builder 进行设置。

    这个 psuedo-sn-p 应该会给你它的要点:

    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];
    

    当然,您也可以添加格式化程序和所有这些东西。

    【讨论】:

      【解决方案3】:

      它在界面生成器中不起作用。但是它以编程方式工作。这是我如何将带有标识符“状态”的 NSTableViewColumn 绑定到我的 NSUserDefaults 中的键:

      斯威夫特:

      tableView.tableColumnWithIdentifier("Status")?.bind("hidden", toObject: NSUserDefaults.standardUserDefaults(), withKeyPath: "TableColumnStatus", options: nil)
      

      目标-C:

      [[self.tableView tableColumnWithIdentifier:@"Status"] bind:@"hidden" toObject:[NSUserDefaults standardUserDefaults] withKeyPath:@"TableColumnStatus" options:nil];
      

      【讨论】:

        【解决方案4】:

        我目前没有完整的答案,但请查看 Bindings。使用 Cocoa Bindings 通常可以做各种各样的事情。

        NSTableColumn 没有可见性绑定,但您可以将宽度设置为 0。

        然后您可以将它绑定到 Null Placeholder,并将此值设置为 0 - 但不要忘记将其他占位符设置为合理的值。

        (正如我所说,这只是一个开始,可能需要一些调整)。

        【讨论】:

          【解决方案5】:

          NSTable 只是绘制表格的类。正如您自己所说,您有一些类将表作为委托,并且该类为表提供要显示的数据。如果您将表数据作为 NSArray 存储在您的委托类中,那么应该很容易找出一列是否为空,不是吗? NSArray 通过委托方法询问您的类有多少列,所以当您被问到时,为什么不查找您有多少列数据并报告该数字而不是您在内部存储的实际列数,然后在被要求时为 (column,row) 提供数据,跳过空列。

          【讨论】:

          • 这很有意义......我可能应该想到这一点。我只是需要更多的可可经验,我想。谢谢您的帮助。 :)
          【解决方案6】:

          没有一次填充所有数据。 NSTableView 不存储数据,它动态地从其数据源(或绑定到对象,如果您使用绑定)中请求它。它只是使用从数据源获取的数据进行绘制并将其丢弃。例如,您不应该看到表格要求提供任何不可见的数据。

          听起来您正在使用数据源?当数据发生变化时,你有责任在表上调用 -reloadData,这有点用词不当。这更像是“使一切无效”。

          也就是说,您应该已经知道数据何时发生变化。这就是您可以计算应该隐藏哪些列的点。

          【讨论】:

            【解决方案7】:

            @amrox - 如果我正确理解您的建议,您是说我应该将值绑定到表中 NSTableColumns 的隐藏属性?这似乎可行,但是我不认为 N​​STableColumn 具有隐藏属性,因为 isHidden 和 setHidden 消息控制列的可见性 - 这告诉我这不是属性,除非我错过了一些东西(这很有可能)。

            【讨论】:

              【解决方案8】:

              我想使用 Cocoa 绑定和实际的 isHidden 标志发布针对 Swift 4 更新的解决方案,而不触及列宽(因为之后您可能需要恢复原始值......)。假设我们有一个复选框来切换某些列的可见性(或者您可以随时以您喜欢的任何其他方式切换下面示例中的 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
                   }
              }
              

              您可能已经注意到,还没有办法像在 XCode10 上那样在 Interface Builder 中绑定 Hidden 标志:您可以看到 EnabledEditable 绑定,但只能通过编程方式访问isHidden 列的标志,因为它在 Swift 中被调用。

              如 cmets 中所述,第二种方法依赖于您必须在选择相关列后通过 Identity 字段上的 Interface Builder 手动设置的列标识符,或者,如果您有一个列名数组,则可以枚举表列并分配标识符和绑定,而不是重复类似的代码行。

              【讨论】:

                【解决方案9】:

                我找到了一个简单的解决方案。

                如果您想使用 Cocoa 绑定技术隐藏任何列:

                1. 在您的 NSArrayController, 实例中创建一个属性/参数/槽/键值,如果您希望隐藏特定列,则该值为 NSNumber 0,否则为任何值。
                2. 将表列对象的maxWidth参数绑定到数据槽,如(1)中所述。我们将使用maxWidth 绑定参数作为消息接收者。
                3. 继承 NSTableColumn:
                import Cocoa
                
                class Column: NSTableColumn {
                
                    /// Observe the binding messages
                    override func setValue(_ value: Any?, forKey key: String) {
                        if key == "maxWidth" && value != nil { // Filters the signal
                            let w = value as! NSNumber // Explores change
                            if w == NSNumber(integerLiteral: 0) {
                                self.isHidden = true
                            } else {
                                self.isHidden = false
                            }
                            return // No propagation for the value change
                        }
                        super.setValue(value, forKey: key) // Propagate the signal
                    }
                    
                }
                
                
                1. 将列的类更改为Column.

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-05-25
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2013-10-31
                  相关资源
                  最近更新 更多