NSTableView选项卡在列之间并移至下一行

时间:2018-11-10 17:14:49

标签: swift macos

用例:

这是一种数据输入方案,用户需要在基于视图的NSTableView的三列中修改数据;数量,项目编号和价格。目的是使用户可以一直握在键盘上,并减少了鼠标在桌子周围进行编辑的需要。

详细的用户界面:

在一行中切换时,下一列应变为选中状态且可编辑,这是(可能是)NSTableView的默认行为。但是,当在最后一列(价格)中进行编辑并跳出时,它应环绕到下一个可用行,第0列(数量),并允许用户继续编辑。

同样,应在一行中支持backtab,并且在第一列(qty)中使用backtab时,应将上一行,最后一列(价格)包裹起来。如果它们位于第0行第0列,则应将其包装到最后一行,最后一列。

因此,基本上,用户应该能够使用Tab键或Backtab键导航和编辑任何行,列。

虽然有几种解决方案,使用keyDown,keyUp,通知等,但很多解决方案是较旧的ObjC代码,而且不是很迅速。

通常情况下,问题应包含某种代码,但由于我有一个可行的解决方案,因此将其作为答案,因此希望它将对将来的读者有所帮助。

问题:

您能否建议一个简单的解决方案,以基于上述参数导航基于视图的表视图。

1 个答案:

答案 0 :(得分:0)

首先是对基于NSTableView的视图进行子类设置,像这样设置

class ItemTableView: NSTableView, NSTableViewDataSource, NSTableViewDelegate, NSTextFieldDelegate {

我有一个名为transactionArray的tableView数据源,它保存要在tableView中显示的项目。我还包括了委托方法

func numberOfRows(in tableView: NSTableView) -> Int

func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView?

在类中,因此它是独立的。

这是处理标签导航的功能

// handle tab and backtab in an editable view based tableView subclass
// will also scroll the edited cell into view when tabbing into view that are outside the viewable area
//ref https://developer.apple.com/documentation/appkit/nscontroltexteditingdelegate/1428898-control
func control(_ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool {
    print(#function)

    //let whichControl = control //this is the tableView textField where the event
                                 //  happened. In this case it will only be the
                                 //  NSTableCellView located within this tableView
    let whichSelector = commandSelector //this is the event; return, tab etc

    //these are the  keypresses we are interested in, tab, backtab, return/enter.
    let tabSelector = #selector( insertTab(_:) )
    //let returnSelector = #selector( insertNewline(_:) ) //use this if you need 
                                                          //custom return/enter handling
    let backtabSelector = #selector( insertBacktab(_:) )

    //if the user hits tab, need to determine where they are. If it's in the last
    //  column, need to see if there is another row and if so, move to next
    //  row, col 0 and go into edit. If it's a backtab in the first column, need
    //  to wrap back to the last row, last col and edit
    if whichSelector == tabSelector {
        let row = self.row(for: textView)
        let col = self.column(for: textView)
        let lastCol = self.tableColumns.count - 1

        if col == lastCol { //we tabbed forward in the last column
            let lastRow = self.transactionArray.count - 1
            var rowToEdit: Int!

            if row < lastRow { //if we are above the last row, go to the next row
                rowToEdit = row + 1

            } else { //if we are at the last row, last col, tab around to the first row, first col
                rowToEdit = 0
            }

            self.editColumn(0, row: rowToEdit, with: nil, select: true)
            self.scrollRowToVisible(rowToEdit)
            return true //tell the OS we handled the key binding
        } else {
            self.scrollColumnToVisible(col + 1)
        }

    } else if whichSelector == backtabSelector {
        let row = self.row(for: textView)
        let col = self.column(for: textView)

        if col == 0 { //we tabbed backward in the first column
            let lastCol = self.tableColumns.count - 1
            var rowToEdit: Int!

            if row > 0 { //and we are after row zero, back up a row and edit the last col
                rowToEdit = row - 1

            } else { // we are in row 0, col 0 so wrap forward to the last col, last row
                rowToEdit = self.transactionArray.count - 1
            }

            self.editColumn(lastCol, row: rowToEdit, with: nil, select: true)
            self.scrollRowToVisible(rowToEdit)
            self.scrollColumnToVisible(lastCol)
            return true
        }  else {
            self.scrollColumnToVisible(col - 1)
        }
    }

    return false //let the OS handle the key binding
}