Cocoa NSTableView&;NSOutlineView在tab键上编辑
我的应用程序有一个Cocoa NSTableView&;NSOutlineView在tab键上编辑,cocoa,macos,keyboard,nstableview,nsoutlineview,Cocoa,Macos,Keyboard,Nstableview,Nsoutlineview,我的应用程序有一个NSOutlineView和一个NSTableView,这两个问题我都有。选中其中一行后,按tab键将第一列置于编辑模式,而不是使下一个键成为第一个响应者。要进入下一个键视图,需要对所有列进行制表 此外,将shift选项卡切换到任一视图会导致最后一列进入编辑模式,需要更多的shift选项卡才能进入其上一个关键点视图 如果有问题,我使用的是自动计算的关键点视图循环,而不是我自己的,我的NSWindow设置为autorecalculatesKeyViewLoop=YES。一旦用户选
NSOutlineView
和一个NSTableView
,这两个问题我都有。选中其中一行后,按tab键将第一列置于编辑模式,而不是使下一个键成为第一个响应者。要进入下一个键视图,需要对所有列进行制表
此外,将shift选项卡切换到任一视图会导致最后一列进入编辑模式,需要更多的shift选项卡才能进入其上一个关键点视图
如果有问题,我使用的是自动计算的关键点视图循环,而不是我自己的,我的NSWindow
设置为autorecalculatesKeyViewLoop=YES
。一旦用户选择编辑列,我希望在列之间进行tab,但我认为tab键触发编辑模式不是标准行为
更新
多亏了下面这些有用的回答,我才算出来。基本上,我在自定义表视图类中重写了-keyDown
,该类处理表视图中的制表和移位制表。然而,要解决在表视图中切换选项卡的问题更为困难。我在自定义表视图的-acceptsFirstResponder
中将布尔属性设置为YES
,如果它从另一个视图接受控件
当当前事件是shift tabkeyDown
事件时,代理的-tableView:shouldEditTableColumn:row
检查是否存在该问题-tableView:shouldEditTableColumn:row
被调用,并且它不是一个shift选项卡事件,它将表视图的属性设置回NO
,因此它仍然可以像往常一样进行编辑
我已经在下面粘贴了完整的解决方案
/* CustomTableView.h */
@interface CustomTableView : NSTableView {}
@property (assign) BOOL justFocused;
@end
这是默认行为。如果未选择任何行,则表视图作为一个整体具有焦点,并且Tab键切换到下一个键视图。如果选择了一行,则表格视图将开始编辑,如果已经编辑,则移动到下一个单元格 发件人: 表现在支持单元间通信 导航如下:
- 向前切换到一个表会聚焦整个表
- 点击空格将尝试在NSButtonCell上点击“performClick:” 所选行(如果只有一行) 该行中的实例
- 如果有第一个“可聚焦”(1)单元,则再次进行标记聚焦
- 如果可以编辑新聚焦的单元格,则将开始编辑
- 点击空格调用单元格上的“performClick:”并设置数据源 值(如果更改)。(二)
- 如果文本单元格正在编辑,则按Enter键将提交编辑并聚焦 将返回到tableview,并且 Tab/Shift Tab将提交编辑 然后执行新的选项卡循环 行为
- 制表符只能通过一行进行制表
- 一旦到达行中的最后一个单元格,tab将把焦点转移到 下一个可聚焦控件
- 在表格中反向切换将选择最后一个可聚焦的单元格
如果要更改此行为,委托方法
tableView:shouldEditTableColumn:row:
可能会有所帮助。如果您真的只想影响Tab键的行为,那么您可能还必须为NSTableView创建子类。我以前也曾处理过这个问题。我的解决方案是将NSTableView
或NSOutlineView
子类化,并覆盖keyDown:
以捕捉那里的制表键按下,然后对其进行操作。多么方便!昨天我自己也在研究这个问题,很高兴看到我所采用的方法得到了一些确认-keyDown:
处理
然而,我对您的方法有一个可能的改进:我发现在shift Tab返回到表时触发编辑的方法是becomeFirstResponder
调用。因此,我对NSTableView子类所做的是:
[[theEvent characters]长度]
,以避免死键出现异常!);如果禁用了选项卡编辑,请根据代码示例转到下一个/上一个视图成为第一响应者:
- (BOOL)becomeFirstResponder {
if (tabEditingDisabled) {
[self display];
return YES;
}
return [super becomeFirstResponder];
}
-(BOOL)成为第一反应者{
如果(选项卡编辑禁用){
[自我展示];
返回YES;
}
返回[超级成为第一响应者];
}
- (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;
}
使用
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)
}
}
}
扩展MyTableView:NSTextFieldDelegate{
func controltextdidediting(uj:Notification){
警卫
让view=obj.object为?NSView,
将textMovementInt=obj.userInfo?[“NSTextMovement”]设为?Int,
让textmovation=nstextmovation(rawValue:textMovementInt)else{return}
让columnIndex=列(用于:视图)
让rowIndex=行(用于:视图)
让newRowIndex:Int
开关文本移动{
案例选项卡:
newRowIndex=rowIndex+1
如果newRowIndex>=numberOfRows{return}
case.backtab:
newRowIndex=rowIndex-1
如果newRowIndex<0{return}
默认值:返回
}
DispatchQueue.main.async{
editColumn(columnIndex,行:newRowIndex,with:nil,select:true)
}
}
}
您还需要设置cell.textField.delegate
,以便实现工作
关于这个棘手的解决方法的博客帖子:在我发布这个问题之前,我曾尝试使用
tableView:shouldEditTableColumn:row:
,但没有找到答案
- (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;
}
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)
}
}
}