Uncommon
Uncommon

Reputation: 3383

Use first column for drag image in NSTableView

I'm implementing drag and drop in a table view, and the problem I'm having is that the drag image is always based on the column where the drag started, but I want to use the image from the first column.

I looked at Apple's TableViewPlayground sample, where the "Complex OutlineView Window" does what I want, but I can't figure out what I'm doing different in terms of setting up the drag.

I put together a simple example at https://github.com/Uncommon/TableTest - if you drag from the second column where it says "stuff", then it looks like you're dragging the word "stuff". What I want is to have the drag image always come from the first column (with the icon and name) regardless of which column you drag from.

In my data source I implement tableView(tableView:,pasteboardWriterForRow:) to enable dragging, but that doesn't include information about what column the drag started in. What am I missing from the example app to make this work?

Upvotes: 1

Views: 564

Answers (3)

S Jensen
S Jensen

Reputation: 17

In response to why dragImageForRows(with:tableColumns:event:offset:) didn't work:

From the Apple documentation:

Note: To support multi-item drags, it is highly recommended to implement the delegate method tableView:pasteboardWriterForRow: instead. Using that method will cause this method to not be called.

Upvotes: 1

alanbi
alanbi

Reputation: 211

The accepted answer didn't work for me. Instead, I had to implement the following optional function in NSTableViewDataSource:

func tableView(_ tableView: NSTableView, draggingSession session: NSDraggingSession, willBeginAt screenPoint: NSPoint, forRowIndexes rowIndexes: IndexSet) {
        // Or whatever cell you want as the drag image
        let cell = tableView.view(atColumn: 0, row: rowIndexes.first!, makeIfNecessary: false) as? NSTableCellView
        session.enumerateDraggingItems(options: .concurrent, for: nil, classes: [NSPasteboardItem.self], searchOptions: [:]) {(draggingItem, idx, stop) in
            if let cell = cell {
                let rect = cell.bounds
                let drag = session.draggingLocation
                // You can customize the image starting point and size here
                draggingItem.setDraggingFrame(NSRect(x: drag.x, y: drag.y, width: rect.width, height: rect.height), contents: cell.draggingImageComponents)
                draggingItem.imageComponentsProvider = {
                    return cell.draggingImageComponents
                }
            }
        }
    }

Credit goes to this answer for providing much of this solution.

Upvotes: 4

Willeke
Willeke

Reputation: 15587

NSTableView drags the column where the drag started, NSOutlineView drags the outline column. If you want to change the image, subclass NSTableView and override dragImageForRows(with:tableColumns:event:offset:).

Upvotes: 0

Related Questions