问题
i found this helpfully tutorial for realize drag an drop with nstabelview: https://drive.google.com/open?id=0B8PBtMQt9GdONzV3emZGQWUtdmM
this works fine.
but i would like to split both table views into differente view controllers and classes with a split view:
one split view controller:
- item 1: viewcontroller with source nstableview (SourceTableView.class)
- item 2: viewcontroller with target nstableview (TargetTableView.class)
how can i do this with this project? i know how can i create a split view controller in storyboard. but i dont know, if i have two different classes, how the iBoutlet SourceTabelView of class SourceTableView.class assign the iBoutlet TargetTableView of class TargetTableView.class
UPDATE
var person = [Person]()
NSManagedObject.class
import Foundation
import CoreData
@objc(Person)
public class Person: NSManagedObject {
@NSManaged public var firstName: String
@NSManaged public var secondName: String
}
回答1:
Example of drag and drop between two table views inside a split view. Dragging inside one table view and multiple selection will work. Hold the Option key to drag a copy.
The datasource of each table view is the view controller inside the split view. Each table view has its own view controller and each view controller controls one table view. Both view controllers are the same NSViewController subclass:
class ViewController: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
@IBOutlet weak var myTableView: NSTableView!
var dataArray: NSMutableArray = ["John Doe", "Jane Doe", "Mary Jane"]
override func viewDidLoad() {
super.viewDidLoad()
myTableView.register(forDraggedTypes: ["com.yoursite.yourproject.yourstringstype"])
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
// NSTableViewDataSource data methods
func numberOfRows(in tableView: NSTableView) -> Int {
return dataArray.count
}
func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {
return dataArray[row] as AnyObject!;
}
// NSTableViewDataSource drag methods
func tableView(_ tableView: NSTableView, writeRowsWith rowIndexes: IndexSet, to pboard: NSPasteboard) -> Bool {
// the dragging destination needs the strings of the rows to add to its own data,
// we, the dragging source, need the indexes of the rows to remove the dropped rows.
pboard.declareTypes(["com.yoursite.yourproject.yourstringstype", "com.yoursite.yourproject.yourindexestype"],
owner: nil)
pboard.setData(NSKeyedArchiver.archivedData(withRootObject: (dataArray as NSArray).objects(at:rowIndexes as IndexSet)), forType: "com.yoursite.yourproject.yourstringstype")
pboard.setData(NSKeyedArchiver.archivedData(withRootObject: rowIndexes), forType: "com.yoursite.yourproject.yourindexestype")
return true
}
func tableView(_ tableView: NSTableView, draggingSession session: NSDraggingSession,
endedAt screenPoint: NSPoint, operation: NSDragOperation) {
// remove the dragged rows if the rows are dragged to the trash or were moved to somewhere else.
var removeRows = false
if operation == .delete {
// trash
removeRows = true
} else if operation == .move {
// check if the point where the rows were dropped is inside our table view.
let windowRect = tableView.convert(tableView.bounds, to: nil)
let screenRect = view.window!.convertToScreen(windowRect)
if !NSPointInRect(screenPoint, screenRect) {
removeRows = true
}
}
if removeRows {
// remove the rows, the indexes are on the pasteboard
let data = session.draggingPasteboard.data(forType: "com.yoursite.yourproject.yourindexestype")!
let rowIndexes = NSKeyedUnarchiver.unarchiveObject(with: data) as! NSIndexSet
(dataArray as NSMutableArray).removeObjects(at: rowIndexes as IndexSet)
tableView.reloadData()
}
}
// NSTableViewDataSource drop methods
func tableView(_ tableView: NSTableView, validateDrop info: NSDraggingInfo, proposedRow row: Int,
proposedDropOperation dropOperation: NSTableViewDropOperation) -> NSDragOperation {
// only accept drop above rows, not on rows.
if dropOperation == .above {
// return move if the dragging source allows move
if info.draggingSourceOperationMask().contains(.move) {
return .move
}
// return copy if the dragging source allows copy
if info.draggingSourceOperationMask().contains(.copy) {
return .copy
}
}
return []
}
func tableView(_ tableView: NSTableView, acceptDrop info: NSDraggingInfo, row: Int,
dropOperation: NSTableViewDropOperation) -> Bool {
// if the rows were moved inside the same table view we do a reorder
var dropRow = row
if info.draggingSource() as AnyObject === myTableView as AnyObject &&
info.draggingSourceOperationMask().contains(.move) {
// remove the rows from their old position
let data = info.draggingPasteboard().data(forType: "com.yoursite.yourproject.yourindexestype")!
let rowIndexes = NSKeyedUnarchiver.unarchiveObject(with: data) as! NSIndexSet
(dataArray as NSMutableArray).removeObjects(at: rowIndexes as IndexSet)
// recalculate the row of the drop
dropRow -= rowIndexes.countOfIndexes(in: NSMakeRange(0, dropRow))
}
// insert the dragged rows
let data = info.draggingPasteboard().data(forType: "com.yoursite.yourproject.yourstringstype")!
let draggedStrings = NSKeyedUnarchiver.unarchiveObject(with: data) as! [Any]
dataArray.insert(draggedStrings, at:IndexSet(integersIn:dropRow..<(dropRow + draggedStrings.count)))
tableView.reloadData()
return true
}
}
To make dragging to the trash work, subclass NSTableView and override:
override func draggingSession(_ session: NSDraggingSession, sourceOperationMaskFor
context: NSDraggingContext) -> NSDragOperation {
let test = super.draggingSession(session, sourceOperationMaskFor: context)
Swift.print("sourceOperationMaskFor \(test)")
switch context {
case .withinApplication:
return [.move, .copy]
case .outsideApplication:
return [.delete]
}
}
p.s. I'm not familiar with Swift and had some trouble with arrays and indexsets so I used NSMutableArray and NSIndexSet.
来源:https://stackoverflow.com/questions/44283444/nstableview-drag-and-drop-split-into-two-classes-and-controllers