是否可以使用箭頭鍵在NSTableView周圍導航NSTableView的可編輯單元並輸入/ tab?例如,我想讓它更像電子表格。帶NSTableView的箭頭鍵
此應用程序的用戶需要編輯相當多的單元(但不是全部),如果不需要雙擊每個單元,我認爲這樣做會更容易。
是否可以使用箭頭鍵在NSTableView周圍導航NSTableView的可編輯單元並輸入/ tab?例如,我想讓它更像電子表格。帶NSTableView的箭頭鍵
此應用程序的用戶需要編輯相當多的單元(但不是全部),如果不需要雙擊每個單元,我認爲這樣做會更容易。
好吧,這是不容易的,但我設法做到了,而不必使用RRSpreadSheet或甚至另一個控件。以下是你需要做的:
創建一個NSTextView
的子類,這將是字段編輯器。在這個例子中,名稱MyFieldEditorClass
將被使用,並且myFieldEditor
將引用該類的一個實例。
給MyFieldEditorClass
添加一個名爲「- (void) setLastKnownColumn:(unsigned)aCol andRow:(unsigned) aRow
」或類似的方法,並讓它將輸入參數值保存在某處。
添加另一個名爲「setTableView:」的方法,並讓它將NSTableView對象保存到某個位置,或者除非有另一種方式從字段編輯器中獲取NSTableView對象,否則使用該方法。
添加另一種稱爲- (void) keyDown:(NSEvent *) event
的方法。這實際上覆蓋了NSResponder
的keyDown:
。源代碼應爲(注意,StackOverflow上的降價正在改變<
和>
到<
和>
):
- (void) keyDown:(NSEvent *) event
{
unsigned newRow = row, newCol = column;
switch ([event keyCode])
{
case 126: // Up
if (row)
newRow = row - 1;
break;
case 125: // Down
if (row < [theTable numberOfRows] - 1)
newRow = row + 1;
break;
case 123: // Left
if (column > 1)
newCol = column - 1;
break;
case 124: // Right
if (column < [theTable numberOfColumns] - 1)
newCol = column + 1;
break;
default:
[super keyDown:event];
return;
}
[theTable selectRow:newRow byExtendingSelection:NO];
[theTable editColumn:newCol row:newRow withEvent:nil select:YES];
row = newRow;
column = newCol;
}
給這個NSTableView的在你的筆尖的委託,並在委託添加方法:
- (BOOL) tableView:(NSTableView *)aTableView shouldEditColumn:(NSTableColumn *) aCol row:aRow
{
if ([aTableView isEqual:TheTableViewYouWantToChangeBehaviour])
[myFieldEditor setLastKnownColumn:[[aTableView tableColumns] indexOfObject:aCol] andRow:aRow];
return YES;
}
最後,給表視圖的主窗口的委託,並添加方法:
- (id) windowWillReturnFieldEditor:(NSWindow *) aWindow toObject:(id) anObject
{
if ([anObject isEqual:TheTableViewYouWantToChangeBehaviour])
{
if (!myFieldEditor)
{
myFieldEditor = [[MyFieldEditorClass alloc] init];
[myFieldEditor setTableView:anObject];
}
return myFieldEditor;
}
else
{
return nil;
}
}
運行該程序,並給它去!
與其強迫NSTableView
做某些事情不是爲了設計,您可能需要考慮使用爲此目的設計的東西。我有一個開源的電子表格控件,它可以做你需要的東西,或者你至少可以擴展它來做你需要的東西:MBTableGrid
在Sequel Pro中,我們使用了一個不同的(在我眼裏更簡單)方法:我們在TableView的委託中實現了control:textView:doCommandBySelector:
。這種方法很難找到 - 它可以在NSControlTextEditingDelegate協議參考中找到。 (請記住,NSTableView是NSControl的一個子類)
長話短說,我們想到了(我們沒有覆蓋左/右箭頭鍵,因爲這些鍵用於在單元格內導航。我們使用選項卡進入左/右)
請注意,這僅僅是從續集臨源代碼片段,並不起作用的是
- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command
{
NSUInteger row, column;
row = [tableView editedRow];
column = [tableView editedColumn];
// Trap down arrow key
if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(moveDown:)])
{
NSUInteger newRow = row+1;
if (newRow>=numRows) return TRUE; //check if we're already at the end of the list
if (column>= numColumns) return TRUE; //the column count could change
[tableContentView selectRowIndexes:[NSIndexSet indexSetWithIndex:newRow] byExtendingSelection:NO];
[tableContentView editColumn:column row:newRow withEvent:nil select:YES];
return TRUE;
}
// Trap up arrow key
else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(moveUp:)])
{
if (row==0) return TRUE; //already at the beginning of the list
NSUInteger newRow = row-1;
if (newRow>=numRows) return TRUE;
if (column>= numColumns) return TRUE;
[tableContentView selectRowIndexes:[NSIndexSet indexSetWithIndex:newRow] byExtendingSelection:NO];
[tableContentView editColumn:column row:newRow withEvent:nil select:YES];
return TRUE;
}
這看起來非常強大,但如果你更好地解釋你在做什麼/如何做,它會有很大的幫助。例如我試過這個,它從來沒有捕捉到向上/向下箭頭鍵 - 雖然它捕獲用戶擊中單元格上的Return,並編輯該單元格? – Adam 2011-05-08 14:00:47
這隻適用於編輯單元格。當您單擊NSTableView的單元格時,窗口字段編輯器將放置在單元格上方,您可以編輯文本。在字段編輯器中編輯文本時,上述消息將發送到表視圖的委託。因爲我們所使用的委託方法的文檔[這裏](http://developer.apple.com/library/mac/documentation/cocoa/reference/NSControlTextEditingDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/NSControlTextEditingDelegate /控制:TextView的:doCommandBySelector :)。 – 2011-05-10 21:22:10
我想在這裏回答的答案,但回覆按鈕似乎不見了,所以當我真的想問一個關於答覆的問題時,我被迫證明了答案。
無論如何,我已經看到了一些覆蓋表視圖的-keyDown事件的答案,該事件聲明子類化TableView,但根據我迄今爲止閱讀的每本Objective-C書以及幾個Apple培訓視頻,你應該很少,如果有一個核心類的子類。實際上,他們中的每一個都表明C程序員對子類化有着濃厚的興趣,而這不是Objective-C的工作原理; Objective-C是關於幫助者和委託而不是繼承的。
那麼,我是否應該忽略對子類的任何響應,因爲這似乎與Objective-C的規則直接相矛盾?
---編輯---
我發現的東西,沒有子的NSTableView的工作。雖然我確實將鏈接上的繼承從NSObject移動到NSResponder,但我並不完全繼承NSTableView。我只是添加了重寫keyDown事件的功能。
我做了我所用從NSResponder類,而不是NSObject的委託繼承類和nextResponder設置爲awakeFromNib該類。然後,我可以使用keydown事件來捕獲按鍵。我當然連接了IBOutlet並在Interface Builder中設置了委託。
這裏是我的代碼需要顯示的關鍵誘捕最低:
頭文件
// AppController.h
#import <Cocoa/Cocoa.h>
@interface AppController : NSResponder {
IBOutlet NSTableView *toDoListView;
NSMutableArray *toDoArray;
}
-(int)numberOfRowsInTableView:(NSTableView *)aTableView;
-(id)tableView:(NSTableView *)tableView
objectValueForTableColumn:(NSTableColumn *)aTableColumn
row:(int)rowIndex;
@end
這裏的M檔。
// AppController.m
#import "AppController.h"
@implementation AppController
-(id)init
{
[super init];
toDoArray = [[NSMutableArray alloc] init];
return self;
}
-(void)dealloc
{
[toDoArray release];
toDoArray = nil;
[super dealloc];
}
-(void)awakeFromNib
{
[toDoListView setNextResponder:self];
}
-(int)numberOfRowsInTableView:(NSTableView *)aTableView
{
return [toDoArray count];
}
-(id)tableView:(NSTableView *)tableView
objectValueForTableColumn:(NSTableColumn *)aTableColumn
row:(int)rowIndex
{
NSString *value = [toDoArray objectAtIndex:rowIndex];
return value;
}
- (void)keyDown:(NSEvent *)theEvent
{
//NSLog(@"key pressed: %@", theEvent);
if (theEvent.keyCode == 51 || theEvent.keyCode == 117)
{
[toDoArray removeObjectAtIndex:[toDoListView selectedRow]];
[toDoListView reloadData];
}
}
@end
對MBTableGrid(和一個慷慨的許可證)的偉大工作,但是這比我所做的要多得多的代碼來做我需要的。 +1爲您投入MBTableGrid的努力。 – dreamlax 2009-03-06 09:34:30