【问题标题】:How to access and sort NSTableView with NSPopUpButton using Swift如何使用 Swift 使用 NSPopUpButton 访问和排序 NSTableView
【发布时间】:2018-04-03 03:10:34
【问题描述】:

为了简单起见,我使用这个 URL 在 Swift (4.1) 中创建了一个 macOS 表: https://medium.com/@kicsipixel/very-simple-view-based-nstableview-in-swift-ab6d7bb30fbb

然后我使用此 URL 能够在表格中拖放行: http://bit.boutique/blog/2015/6/8/drag-sorting-nstableview-rows-in-swift/

我能够确定如何使用此 URL 双击编辑单元格: Double click an NSTableView row in Cocoa?

如果表格有多个列,要确定正在编辑哪一列,我必须向 Apple 提出问题请求。他们向我提供了这段未记录的代码(并建议我打开文档错误报告,我照做了)。

func control(_ control: NSControl, textShouldEndEditing fieldEditor: NSText) -> Bool {
    print("textShouldEndEditing text is " + (fieldEditor.string) + " [" +  String(describing:  tableView.row(for: control)) + "][" + String(describing: tableView.column(for: control) ) + "]" )
    return true
} // textShouldEndEditing

我把所有这些拼凑在一起,我认为我已经完成了。然后我尝试在我的表中添加另一列,即 NSPopUpButton。当我这样做时,表格显示正常,但我不能再拖放行。

函数 viewFor、writeRowsWith 和 DraggingSessionendedAt 被调用,但是 validateDrop 和 acceptDrop 不是。

// MARK: tableView
func numberOfRows(in tableView: NSTableView) -> Int {

    tableView.doubleAction = #selector(doubleClickOnResultRow)

    initPrefs()

    tableView.tableColumns[0].title = localizedString(forKey: "CityNames_") + ":"
    tableView.tableColumns[1].title = localizedString(forKey: "CityDisplayNames_") + ":"
    tableView.tableColumns[2].title = localizedString(forKey: "weatherSource_") + ":"
    tableView.tableColumns[3].title = localizedString(forKey: "API Key 1:_")
    tableView.tableColumns[4].title = localizedString(forKey: "API Key 2:_")

    return locationInformationArray.count
} // numberOfRows

// Populate table
func tableView(_ tableView: NSTableView,
               viewFor tableColumn: NSTableColumn?,
               row: Int) -> NSView? {
    var cell: NSTableCellView

    //print("viewFor: row=" + String(describing:  row), column=" + String(describing:  column) )

    var column = -1
    if tableColumn == tableView.tableColumns[0] {
        column = 0
    } else  if tableColumn == tableView.tableColumns[1] {
        column = 1
    } else  if tableColumn == tableView.tableColumns[2] {
        column = 2
    } else  if tableColumn == tableView.tableColumns[3] {
        column = 3
    } else {
        column = 4
    }

    if (column != 2) {
        cell = (tableView.makeView(withIdentifier: tableColumn!.identifier, owner: nil) as? NSTableCellView)!
        cell.textField?.stringValue = locationInformationArray[row][column]
    } else { // Column 2/Weather Source
        let result = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "weatherSource"), owner: nil) as! NSPopUpButton
        InitWeatherSourceButton(weatherSourceButton: result)
        result.selectItem(at: Int(locationInformationArray[row][column])!)
        return result
    }

    return cell
} // viewFor (Populate)

// Drag "from"
func tableView(_ tableView: NSTableView,
               writeRowsWith writeRowsWithIndexes: IndexSet,
               to toPasteboard: NSPasteboard) -> Bool {
    print("in writeRowsWith")
    let data = NSKeyedArchiver.archivedData(withRootObject: [writeRowsWithIndexes])
    toPasteboard.declareTypes([NSPasteboard.PasteboardType(rawValue: MyRowType)], owner:self)
    toPasteboard.setData(data, forType:NSPasteboard.PasteboardType(rawValue: MyRowType))

    return true
} // writeRowsWith (From Row)

// Drag "to"
func tableView(_ tableView: NSTableView,
               validateDrop info: NSDraggingInfo,
               proposedRow row: Int,
               proposedDropOperation dropOperation: NSTableView.DropOperation) -> NSDragOperation {

    print("in validateDrop, proposedRow=" + String(describing: row))
    tableView.setDropRow(row, dropOperation: NSTableView.DropOperation.above)
    return NSDragOperation.move
} // validateDrop

// Drag "to"
func tableView(_ tableView: NSTableView,
               acceptDrop info: NSDraggingInfo,
               row: Int,
               dropOperation: NSTableView.DropOperation) -> Bool {
    print("in acceptDrop, row=" + String(describing: row))
    let pasteboard = info.draggingPasteboard()
    let rowData = pasteboard.data(forType: NSPasteboard.PasteboardType(rawValue: MyRowType))

    if(rowData != nil) {
        var dataArray = NSKeyedUnarchiver.unarchiveObject(with: rowData!) as! Array<IndexSet>,
        indexSet = dataArray[0]

        let movingFromIndex = indexSet.first

        //tableView.moveRow(at: movingFromIndex!, to: row) // Can only be done if the Array doesn't need to get re-populated
        _moveItem(from: movingFromIndex!, to: row, array: &locationInformationArray)

        tableView.reloadData()
        return true
    }
    else {
        return false
    }
} // acceptDrop

func tableView(_ tableView: NSTableView,
               draggingSession session: NSDraggingSession,
               endedAt screenPoint: NSPoint,
               operation: NSDragOperation) {
        return
}


// Move row in table array
func _moveItem(from: Int,
               to: Int,
               array: inout [[String]]) {
    //print("in _moveItem")
    let item = array[from]
    array.remove(at: from)

    if(to > array.endIndex) {
        array.append(item)
    }
    else {
        array.insert(item, at: to)
    }
} // _moveItem

而且最后,我无法确定 NSPopUpButton 正在访问哪一行(和哪一列):

@IBAction func popUpSelectionDidChange(_ sender: NSPopUpButton) {
    print("Selected item=" + String(describing: sender.indexOfSelectedItem) + " [" +  String(describing:  tableView.row(for: tableView)) + "][" + String(describing: tableView.column(for: tableView)) + "]" )
}

行和列总是-1。

关于如何解决我剩下的两个问题(在 Swift 中)、拖放以及选择了哪个弹出按钮有什么建议?

谢谢。

【问题讨论】:

  • 为什么需要代码来启用双击开始编辑?您想从哪里知道正在编辑哪一列?要调试拖放,我们需要所有相关代码。
  • NSTextFieldNSPopUpButtonNSControl 的子类。 tableView.row(for: control)tableView.column(for: control) 对两者都有效。
  • Wileke - 感谢您的 (for: control) 注释,现在可以使用:@IBAction func popUpSelectionDidChange(_ sender: NSPopUpButton) { print("Selected item=" + String(describing: sender. indexOfSelectedItem) + " [" + String(describing: tableView.row(for: sender)) + "][" + String(describing: tableView.column(for: sender)) + "]" ) } 至于拖拽和滴,这是我的完整代码集,我已经编辑了我的原始帖子。
  • Wileke - 如果您想发布您的第二条评论作为答案(NSControl 的子类),我会接受它,因为它解决了点击位置。 Rob Mayoff 提供的答案解决了第二部分(拖放)。

标签: swift macos nstableview nspopupbutton nstablecellview


【解决方案1】:

如果您将MyRowType 的类型更改为NSPasteboard.PasteboardType,您将节省一些代码,例如

fileprivate let MyRowType = NSPasteboard.PasteboardType("com.ed-danley.MyRowType")

tableView:writeRowsWithIndexes:toPasteboard:tableView:draggingSession:endedAtPoint: 消息用于拖动源支持(检查 NSTableView.h 以验证)。

tableView:validateDrop:proposedRow:proposedDropOperation:tableView:acceptDrop:row:dropOperation: 消息用于拖动目标支持。我的猜测是您尚未将表格配置为拖动目标。

要将表格视图配置为拖动目标,您必须调用tableView.registerForDraggedTypes([MyRowType])。这实际上是NSView 上的一个方法,它告诉 AppKit 你希望这个视图成为一个拖动目的地。您只需在表格视图上调用一次,因此根据您使用的控制器类型,viewDidLoadwindowDidLoad 可能是合适的位置。

【讨论】:

  • 谢谢罗伯。但是,对于“您尚未将表配置为拖动目标”,拖放工作直到我添加了弹出窗口,如果我删除它,它会再次工作。有没有不同的方式来配置它与弹出窗口?
  • Ron - fileprivate 和 registerForDraggedTypes 成功了。谢谢你。我赞成答案,但我没有足够的分数被接受。
猜你喜欢
  • 2020-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-22
  • 2018-01-27
相关资源
最近更新 更多