[Mac] NSTableView - セル編集終了時のイベントを掴む

2010年11月28日日曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

公式リファレンスの Q&A に解説がある。
Technical Q&A QA1551: Detecting the start and end edit sessions of a cell in NSTableView.
方法は Delegate と Notification の2つの方法がある。


NSControlTextEditingDelegate


NSTableViewDelegate を見ると編集開始時に呼ばれるメソッドしか無いのでセル編集終了時のイベントが取れないように見える。
- (BOOL)tableView:(NSTableView *)aTableView shouldEditTableColumn:
(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
NSTableViewDelegate Protocol Reference

が、NSTableViewDelegate の親プロトコル である NSControlEdtingDelegate に必要なメソッドがあるのでそちらを使うことができる。
- (BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)fieldEditor;
- (BOOL)control:(NSControl *)control textShouldEndEditing:(NSText *)fieldEditor;
NSControlTextEditingDelegate Protocol Reference


name:NSControlTextDidEndEditingNotification


Deletate とは別に Notification を使うこともできる。QA1551より転載:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(editingDidEnd:)
        name:NSControlTextDidEndEditingNotification object:nil];

- (void)editingDidEnd:(NSNotification *)notification
{
    NSTableView* tableView = (NSTableView*)[notification object];
     :
}
NSTableView は -object メソッドで取得できる。


呼び出しシーケンス


こんな感じ。
セルをダブルクリックして編集開始
 |
 | → tableView:shouldEditTableColumn:row:
 ↓
キー入力開始
 |
 |→ control:textShouldBeginEditing:
 ↓
リターンもしくはフォーカスを移動して編集終了
 |
 |→ control:textShouldEndEditing:
 ↓
NSControlTextDidEndEditingNotification


備考


Delegate は便利なのだが名前に "Should" が含まれていることからわかるように編集が完全に終了した後呼び出されるわけではない。このメソッドで NO を返すと編集をキャンセルすることができる。Cocoa Bindings を使っている場合このタイミングが問題になる場合がある。例えば NSArrayController を使っていて、この Delegate が呼ばれた時にモデルの内容を保存する場合など。このタイミングでは NSTableView のセルでの編集内容がまだバインド先のモデルに反映されていない為、編集前の古い内容での保存になってしまう。この場合、編集完了のタイミングを掴むには Delegate ではなく Notification の方を使う。NSControlTextDidEndEditingNotification を使えば編集内容がモデルに反映された後のタイミングで処理を行うことができる。


サンプル


簡単に動作確認できるサンプルを用意した。編集時にイベントがデバッグコンソールに表示される。
[16744:a0f] -[AppController tableView:shouldEditTableColumn:row:]
|<NSTableView: 0x10051c1a0>|<NSTableColumn: 0x10051d360> identifier: name|4
[16744:a0f] -[AppController control:textShouldBeginEditing:]|<NSTableView:
 0x10051c1a0><<NSTextView: 0x100565e90>
    Frame = {{1.00, 77.00}, {171.00, 17.00}}, Bounds = {{0.00, 0.00}, {171.00, 17.00}}
    Horizontally resizable: YES, Vertically resizable: YES
    MinSize = {171.00, 17.00}, MaxSize = {40000.00, 40000.00}
[16744:a0f] -[AppController control:textShouldEndEditing:]|<NSTableView: 
0x10051c1a0>|<NSTextView: 0x100565e90>
    Frame = {{1.00, 77.00}, {171.00, 17.00}}, Bounds = {{0.00, 0.00}, {171.00, 17.00}}
    Horizontally resizable: YES, Vertically resizable: YES
    MinSize = {171.00, 17.00}, MaxSize = {40000.00, 40000.00}
[16744:a0f] -[AppController editingDidEnd:]|NSConcreteNotification 0x10016c7a0
 {name = NSControlTextDidEndEditingNotification; object = <NSTableView: 0x10051c1a0>; userInfo = {
    NSFieldEditor = "<NSTextView: 0x100565e90>\n    Frame = {{1.00, 77.00},
 {171.00, 17.00}}, Bounds = {{0.00, 0.00}, {171.00, 17.00}}\n
    Horizontally resizable: YES, Vertically resizable: YES\n
    MinSize = {171.00, 17.00}, MaxSize = {40000.00, 40000.00}\n";
    NSTextMovement = 16;
}}

ソースコードは GitHub からどうぞ。
NSTableViewSample at 2010-11-28 from xcatsan/MacOSX-Sample-Code - GitHub

Responses

Leave a Response

人気の投稿(過去 30日間)