Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cocoa/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Cocoa NSTableView&;NSOutlineView在tab键上编辑_Cocoa_Macos_Keyboard_Nstableview_Nsoutlineview - Fatal编程技术网

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 tab
keyDown
事件时,代理的
-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子类所做的是:

  • 添加合成属性以控制是否禁用选项卡编辑行为
  • 按下键时,检查tab的第一个字符(同时检查
    [[theEvent characters]长度]
    ,以避免死键出现异常!);如果禁用了选项卡编辑,请根据代码示例转到下一个/上一个视图
  • 覆盖
    成为第一响应者
    :
    - (BOOL)becomeFirstResponder {
        if (tabEditingDisabled) {
            [self display];
            return YES;
        }
        return [super becomeFirstResponder];
    }
    -(BOOL)成为第一反应者{
    如果(选项卡编辑禁用){
    [自我展示];
    返回YES;
    }
    返回[超级成为第一响应者];
    }
    
  • 这将保留tableview子类中的所有代码,使委托更干净:)

    唯一的危险是我不知道NSTableView在成为第一反应者方面还能做些什么;我没有注意到任何东西断裂,但…

    这对我来说很有效:

    - (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)
            }
        }
    }