質問
表示されるデータに基づいて、NSTableView の一部の列を動的に非表示/表示したいと考えています。基本的に、列が空の場合はその列を非表示にしたいと考えています。現在、テーブルのデリゲートとしてコントローラー クラスをテーブルに設定しています。
何か案は?Interface Builder で列を非表示に設定できることはわかりましたが、列を調べて空かどうかを確認する時間がないようです。テーブル内のすべてのデータが設定される前または後に呼び出されます。
解決
NSTable は、テーブルを描画するクラスにすぎません。あなた自身が言ったように、テーブルにデリゲートとして与えるクラスがあり、このクラスは表示するデータをテーブルにフィードします。デリゲート クラス内でテーブル データを NSArray として保存すると、1 つの列が空かどうかを簡単に見つけることができるはずです。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)
目標-C:
[[self.tableView tableColumnWithIdentifier:@"Status"] bind:@"hidden" toObject:[NSUserDefaults standardUserDefaults] withKeyPath:@"TableColumnStatus" options:nil];
現時点では完全な答えはありませんが、バインディングを調べてください。一般に、Cocoa バインディングを使用してあらゆる種類のことが可能です。
NSTableColumn には Visibility バインディングはありませんが、幅を 0 に設定できる場合があります。
次に、それを Null プレースホルダーにバインドし、この値を 0 に設定します。ただし、他のプレースホルダーを適切な値に設定することを忘れないでください。
(先ほども言いましたが、これは単なる始まりであり、多少の調整が必要になる可能性があります)。
すべてのデータが一度に設定されるわけではありません。NSTableView はデータを保存せず、データ ソース (バインディングを使用している場合はバインド先のオブジェクト) からデータを動的に要求します。データ ソースから取得したデータを使用して描画するだけで、それは無視されます。たとえば、目に見えないもののデータを要求するテーブルは表示されるべきではありません。
データソースを使用しているようですね?データが変更された場合、テーブルに対して -reloadData を呼び出すのはユーザーの責任です。これは少し誤解があります。それは「すべてを無効にする」に似ています。
つまり、データがいつ変更されるかをすでに知っている必要があります。この時点で、どの列を非表示にするかを計算できます。
@amrox - あなたの提案を正しく理解している場合、テーブル内のNSTableColumnsの非表示プロパティに値をバインドする必要があると言っていますか?それは機能するように見えますが、isHiddenとsetHiddenメッセージが列の可視性を制御するため、NSTableColumnに隠しプロパティがあるとは思えません。これは、何かが欠けている場合を除き、これがプロパティではないことを示しています(その可能性は十分にあります)。
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 で呼び出される列のフラグ。
コメントに記載されているように、2 番目の方法は、関連する列を選択した後、Interface Builder を使用して ID フィールドに手動で設定する必要がある列識別子に依存します。または、列名の配列がある場合は、テーブルの列を列挙して、同様のコード行を繰り返す代わりに、識別子とバインディングを使用します。