简体   繁体   English

如何使用Swift使用NSPopUpButton访问和排序NSTableView

[英]How to access and sort NSTableView with NSPopUpButton using Swift

To keep it simple, I used this URL to create a macOS table in Swift (4.1): https://medium.com/@kicsipixel/very-simple-view-based-nstableview-in-swift-ab6d7bb30fbb 为简单起见,我使用此URL在Swift(4.1)中创建了macOS表: https : //medium.com/@kicsipixel/very-simple-view-based-nstableview-in-swift-ab6d7bb30fbb

I then used this URL to be able to drag and drop rows in the table: http://bit.boutique/blog/2015/6/8/drag-sorting-nstableview-rows-in-swift/ 然后,我使用此URL来拖放表中的行: http : //bit.boutique/blog/2015/6/8/drag-sorting-nstableview-rows-in-swift/

I able to determine how to double click to edit a cell by using this URL: Double click an NSTableView row in Cocoa? 我可以确定如何通过使用以下URL双击以编辑单元格: 双击Cocoa中的NSTableView行?

If the table has multiple columns, to determine what column was being edited, I had to open a problem request with Apple. 如果表中有多列,要确定正在编辑的列,我必须向Apple打开一个问题请求。 They provided me with this undocumented piece of code (and suggested I open a documentation bug report, which I did). 他们为我提供了这段未记录的代码(并建议我打开一份文档错误报告,该报告确实如此)。

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

I pieced all of that together and I thought I was done. 我把所有这些拼凑在一起,以为我完成了。 I then attempted to add another column to my table, an NSPopUpButton. 然后,我尝试向表中添加另一列NSPopUpButton。 When I did that the table displays fine but I can no longer drag and drop the rows. 当我这样做时,表格显示正常,但是我无法再拖放行。

The functions viewFor, writeRowsWith, and DraggingSession endedAt is called but validateDrop and acceptDrop are not. 函数viewFor,writeRowsWith和DraggingSession的Ended被调用,但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

And finally, I can't determine which row (and column) is being access by the NSPopUpButton: 最后我也不能确定哪一行(和列)是由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)) + "]" )
}

Both the row and column are always -1. 行和列都始终为-1。

Any suggestions on how to solve both of my remaining issues (in Swift), drag and drop and which Pop Up button was selected? 关于如何解决我剩下的两个问题(在Swift中),拖放以及选择了哪个弹出按钮的任何建议?

Thanks. 谢谢。

You'll save some code if you change the type of MyRowType to NSPasteboard.PasteboardType , eg 如果将MyRowType的类型MyRowTypeNSPasteboard.PasteboardType ,则将保存一些代码,例如

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

The tableView:writeRowsWithIndexes:toPasteboard: and tableView:draggingSession:endedAtPoint: messages are for dragging source support (check NSTableView.h to verify). tableView:writeRowsWithIndexes:toPasteboard:tableView:draggingSession:endedAtPoint:消息用于拖动源支持(请检查NSTableView.h进行验证)。

The tableView:validateDrop:proposedRow:proposedDropOperation: and tableView:acceptDrop:row:dropOperation: messages are for dragging destination support. tableView:validateDrop:proposedRow:proposedDropOperation:tableView:acceptDrop:row:dropOperation:消息用于拖动目标支持。 My guess is you have not configured the table as a drag destination. 我的猜测是您尚未将表配置为拖动目标。

To configure the table view as a drag destination, you must call tableView.registerForDraggedTypes([MyRowType]) . 要将表格视图配置为拖动目标,必须调用tableView.registerForDraggedTypes([MyRowType]) This is actually a method on NSView and it's what tells AppKit that you want this view to be a drag destination. 这实际上是NSView上的一种方法,它告诉AppKit您希望此视图成为拖动目标。 You only need to call this once on the table view, so depending on what kind of controller you're using, viewDidLoad or windowDidLoad may be the appropriate place. 您只需要在表视图上调用一次,因此视您使用的是哪种控制器而定, viewDidLoadwindowDidLoad可能是合适的位置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM