環境
NSArrayController によって管理される 2 列のセル ベースの NSTableView があります。
- 最初の列には、値が有効かどうかを示すチェックボックスが表示されます。
- 2 番目の列は要素の名前を表します。
ビューは NSSearchField にリンクされているため、検索文字列を列 2 の文字列と比較する述語に基づいてフィルター処理されます。
ビューは正しく表示され、検索文字列が変更されたときに意図したとおりにフィルタリングされます。
要件
ユーザーが最大 5 行を有効にできるようにする必要があります。これを達成するために、バッキング アレイの変更を監視し、有効なエントリの量を追跡しています。カウントが 5 を超えた場合は、アラートでユーザーに通知し、選択された行インデックスを取得してバッキング アレイでそのインデックスを無効にすることで、以前に有効にしたエントリの選択を解除します。[willChange.. ..didChange] KVO ブロックでこれを行います。
これは、ビューがソートされていない場合は意図したとおりに機能しますが、選択された行が配列内の適切なインデックスに対応していないため、明らかに問題が発生します。
したがって、次のコードを使用して、ビューがフィルター処理されている場合 (検索文字列が空でない場合) に、選択したセルの文字列値を取得します。次に、配列をトラバースし、文字列に一致するエントリを無効にします。
NSInteger selectedRow = [_tv_TableView selectedRow];
NSTableColumn* column= [_tv_TableView tableColumns][1];
NSCell* cell = [column dataCellForRow:row];
NSString* cellValue = (NSString*)[cell stringValue];
return cellValue;
問題
選択された行は常に正確ですが、代表セルから値を取得することは正確ではありません。最初は返された値が正しいように見えますが、他の行を選択すると、選択したインデックスがまだ正しい場合でも、次の行からデータが返されます。また、ビューのいくつかの行から値を返すことも確認しました。
アップデート
さらにテストした結果、初めてフィルターを適用すると機能するように見えますが、別の文字列によるフィルター処理では、その特定のフィルターで最初に選択されたセルのセル値が保持されます。
すなわち:
- ウィンドウを読み込んで6つのアイテムを選択
- 6 番目のアイテムの選択が解除され、ユーザーに警告されました
- フィルターを適用
- 新しい6番目のアイテムを選択してください
- 6 番目のアイテムの選択が解除され、ユーザーに警告されました
- 同じフィルターで別の 6 番目のアイテムを選択してください
- 6 番目のアイテムの選択が解除され、ユーザーに警告されました
- 新しいフィルタを入力してください
- 新しい6番目のアイテムを選択してください
- 6 番目のアイテムの選択が解除され、ユーザーに警告されました
- 同じフィルターから新しい 6 番目のアイテムを選択
- 選択したインデックスは正しいですが、選択した行の値は前の選択と同じです
- 正しいエントリが選択解除されていないため、ユーザーは繰り返し警告を受け、6 つのエントリが永続的に選択されました。
ただし、以前に選択されたアイテムではなく、次の行の値が返される場合もあります。
質問
私の質問は次のとおりです。
- フィルター処理されたリストに対して正しい方法で選択された行を取得していますか?
- リストがソートされている場合でも、選択した行に基づいて列 2 の文字列値を一貫して取得するにはどうすればよいですか?
お時間をいただきありがとうございます。
解決
セルを取得するコードを次のように変更して、これを解決しました。
NSInteger selectedRow = [_tv_TableView selectedRow];
NSTableColumn* column= [_tv_TableView tableColumns][1];
NSCell* cell = [column dataCellForRow:row];
NSString* cellValue = (NSString*)[cell stringValue];
return cellValue;
に:
NSCell* cell = [_tv_TableView preparedCellAtColumn:1 row:row];
NSString* cellValue = (NSString*)[cell stringValue];
return cellValue;