我的应用有一个NSOutlineView
和一个NSTableView
,我遇到了同样的问题。如果选择了一行,则按Tab键会将第一列置于编辑模式,而不是使下一个键视图成为第一响应者。要进入下一个关键视图,您需要标记所有列。
此外,将Shift-tabbing转换为任一视图会导致 last 列进入编辑模式,从而需要更多shift-tabs进入其先前的关键视图。
如果重要,我使用自动计算的关键视图循环,而不是我自己的,我的NSWindow
设置为autorecalculatesKeyViewLoop = YES
。一旦用户选择编辑列,我希望在列之间进行选项卡,但我不认为选项卡键的标准行为是触发编辑模式。
更新
感谢下面的有用回复,我解决了这个问题。基本上,我在自定义表视图类中重写-keyDown
,该类处理表格视图中的Tab键和shift-tabbing。然而,将换档标签解决到表格视图中更为困难。我在自定义表视图的YES
中设置了一个布尔属性-acceptsFirstResponder
,如果它正在接受来自另一个视图的控制。
当前事件是shift-tab -tableView:shouldEditTableColumn:row
事件时,委托人keyDown
会检查该事件。 -tableView:shouldEditTableColumn:row
被调用并且它不是shift-tab事件,它将表视图的属性设置回NO
,因此它仍然可以照常编辑。
我已粘贴下面的完整解决方案。
/* CustomTableView.h */
@interface CustomTableView : NSTableView {}
@property (assign) BOOL justFocused;
@end
/* CustomTableView.m */
@implementation CustomTableView
@synthesize justFocused;
- (BOOL)acceptsFirstResponder {
if ([[self window] firstResponder] != self) {
justFocused = YES;
}
return YES;
}
- (void)keyDown:(NSEvent *)theEvent
{
// Handle the Tab key
if ([[theEvent characters] characterAtIndex:0] == NSTabCharacter) {
if (([theEvent modifierFlags] & NSShiftKeyMask) != NSShiftKeyMask) {
[[self window] selectKeyViewFollowingView:self];
} else {
[[self window] selectKeyViewPrecedingView:self];
}
}
else {
[super keyDown:theEvent];
}
}
@end
/* TableViewDelegate.m */
. . .
- (BOOL)tableView:(NSTableView *)tableView shouldEditTableColumn:(NSTableColumn *)tableColumn
row:(NSInteger)row
{
NSEvent *event = [NSApp currentEvent];
BOOL shiftTabbedIn = ([event type] == NSKeyDown
&& [[event characters] characterAtIndex:0] == NSBackTabCharacter);
if (shiftTabbedIn && ((CustomTableView *)tableView).justFocused == YES) {
return NO;
} else {
((CustomTableView *)tableView).justFocused = NO;
}
return YES;
}
. . .
答案 0 :(得分:7)
这是默认行为。如果没有选择行,则表视图整体具有焦点,Tab键切换到下一个键视图。如果选择了行,则表视图开始编辑或移动到下一个单元格(如果已编辑)。
表现在支持单元间 导航如下:
- 向前跳转到表格会聚焦整个表格。
- Hitting Space将尝试在NSButtonCell上执行'performClick:' 选中的行,如果只有一行 该行中的实例。
- Tabbing会再次聚焦第一个“可聚焦”(1)单元格(如果有)。
- 如果可以编辑新聚焦的单元格,则将开始编辑。
- 命中空间在单元格上调用'performClick:'并设置数据源 之后的价值,如果改变了。 (2)
- 如果正在编辑文本单元格,按Enter键将提交编辑和焦点 将返回到tableview,并且 Tab / Shift-tab将提交编辑 然后执行新的制表循环 行为。
- Tabbing只会标记一行
- 一旦到达连续的最后一个单元格,选项卡将关注焦点 下一个可控制的控制。
- 返回表格将选择最后一个可聚焦单元格。
如果要更改此行为,委派方法tableView:shouldEditTableColumn:row:
可能会有所帮助。如果您真的只想影响Tab键的行为,则可能还必须继承NSTableView
。
答案 1 :(得分:2)
我之前也必须处理这个问题。我的解决方案是继承NSTableView
或NSOutlineView
并覆盖keyDown:
以抓住Tab键,然后按下它们。
答案 2 :(得分:0)
多么方便!我昨天只是在看这个问题,很高兴看到我采取的方法有一些确认 - keyDown:
处理。
但是,我对你的方法有一个小小的改进:我得出结论,在转换表上触发编辑的方法是becomeFirstResponder
调用。所以我在NSTableView子类上所做的是:
[[theEvent characters] length]
以避免死键的例外!)。如果禁用了选项卡编辑,请根据您的代码示例继续查看下一个/上一个视图。becomeFirstResponder
:
- (BOOL)becomeFirstResponder { if (tabEditingDisabled) { [self display]; return YES; } return [super becomeFirstResponder]; }
这会保留tableview子类中的所有代码,使委托更清晰:)
唯一的危险是我不知道NSTableView在becomeFirstResponder中做了什么;我没有注意到任何破坏,但是......
答案 3 :(得分:0)
这对我有用:
- (BOOL)tableView:(NSTableView *)tableView shouldEditTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
NSEvent *e = [NSApp currentEvent];
if (e.type == NSKeyDown && e.keyCode == 48) return NO;
return YES;
}
答案 4 :(得分:0)
使用keyDown
的解决方案对我不起作用。也许是因为它用于基于单元格的表视图。
我在Swift中基于视图的表视图的解决方案如下:
extension MyTableView: NSTextFieldDelegate {
func controlTextDidEndEditing(_ obj: Notification) {
guard
let view = obj.object as? NSView,
let textMovementInt = obj.userInfo?["NSTextMovement"] as? Int,
let textMovement = NSTextMovement(rawValue: textMovementInt) else { return }
let columnIndex = column(for: view)
let rowIndex = row(for: view)
let newRowIndex: Int
switch textMovement {
case .tab:
newRowIndex = rowIndex + 1
if newRowIndex >= numberOfRows { return }
case .backtab:
newRowIndex = rowIndex - 1
if newRowIndex < 0 { return }
default: return
}
DispatchQueue.main.async {
self.editColumn(columnIndex, row: newRowIndex, with: nil, select: true)
}
}
}
您还需要设置cell.textField.delegate
,以使实现可行。
我有关此棘手解决方法的博客文章:https://samwize.com/2018/11/13/how-to-tab-to-next-row-in-nstableview-view-based-solution/