NSTableView: обнаружение щелчка мыши вместе со строкой и столбцом

Я пытаюсь обнаружить, когда щелчок мыши происходит в NSTableView, и когда он это делает, чтобы определить строку и столбец ячейки, на которую было нажато.

До сих пор я пытался использовать NSTableViewSelectionDidChangeNotification, но есть две проблемы:

  • Он запускается только при изменении выбора, тогда как я хочу, чтобы каждый щелчок мыши, даже если он находится в текущей выбранной строке.
  • Свойства clickedRow и clickedColumn для NSTableView равны -1, когда вызывается мой делегат.

Есть ли лучший (и правильный) способ сделать это?

Ответы

Ответ 1

Чтобы поймать пользователя, щелкающего по строке (только, когда пользователь щелкает по строке, а не когда она выбирается программно):

Подкласс вашего NSTableView и объявить протокол

MyTableView.h

@protocol ExtendedTableViewDelegate <NSObject>

- (void)tableView:(NSTableView *)tableView didClickedRow:(NSInteger)row;

@end

@interface MyTableView : NSTableView

@property (nonatomic, weak) id<ExtendedTableViewDelegate> extendedDelegate;

@end

MyTableView.m

Обрабатывать событие нажатия мыши (обратите внимание, что обратный вызов делегата не вызывается, когда пользователь щелкает снаружи, может быть, вы тоже захотите это обработать, в этом случае просто закомментируйте условие " if (clickedRow != -1) ")

- (void)mouseDown:(NSEvent *)theEvent {

    NSPoint globalLocation = [theEvent locationInWindow];
    NSPoint localLocation = [self convertPoint:globalLocation fromView:nil];
    NSInteger clickedRow = [self rowAtPoint:localLocation];

    [super mouseDown:theEvent];

    if (clickedRow != -1) {
        [self.extendedDelegate tableView:self didClickedRow:clickedRow];
    }
}

Приведите ваш WC, VC в соответствие с ExtendedTableViewDelegate.

@interface MyViewController : DocumentBaseViewController<ExtendedTableViewDelegate, NSTableViewDelegate,  NSTableViewDataSource>

установите extendedDelegate MyTableView для вашего WC, VC (MyViewController)

где-то в MyTableView.m

self.myTableView.extendedDelegate = self

Реализуйте обратный вызов в делегате (MyViewController.m)

- (void)tableView:(NSTableView *)tableView didClickedRow:(NSInteger)row {
    // have fun
}

Ответ 2

Существует простой способ.

Протестировано с Swift 3.0.2 на macOS 10.12.2 и Xcode 8.2.1

Пусть

tableView.action = #selector(onItemClicked)

Тогда

@objc private func onItemClicked() {
    print("row \(tableView.clickedRow), col \(tableView.clickedColumn) clicked")
}

Ответ 3

Я бы предпочел сделать следующее.

Переопределить

-(BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row;

Обеспечить супер-реализацию;

RequiredRow = row;
RequiredColumn = [tableView clickedColumn];

Надеюсь, что это поможет.

Ответ 4

Если кто-то ищет версию ответа Swift 3 Питера Лапису.

Добавьте расширение для NSTableView (NSTableView + Clickable.swift):

import Foundation
import Cocoa

extension NSTableView {
    open override func mouseDown(with event: NSEvent) {
        let globalLocation = event.locationInWindow
        let localLocation = self.convert(globalLocation, to: nil)
        let clickedRow = self.row(at: localLocation)

        super.mouseDown(with: event)

        if (clickedRow != -1) {
            (self.delegate as? NSTableViewClickableDelegate)?.tableView(self, didClickRow: clickedRow)
        }
    }
}

protocol NSTableViewClickableDelegate: NSTableViewDelegate {
    func tableView(_ tableView: NSTableView, didClickRow row: Int)
}

Затем, чтобы использовать его, убедитесь, что вы реализуете новый протокол делегатов:

extension MyViewController: NSTableViewClickableDelegate {
    @nonobjc func tableView(_ tableView: NSTableView, didClickRow row: Int) {
        Swift.print("Clicked row \(row)")
    }
}

Атрибут @nonobjc отключает предупреждение о том, что он близок к didClick.

Ответ 5

На всякий случай кто-то искал его в SWIFT и/или для NSOutlineView.

Основываясь на инструкциях @Peter Lapisu.

class MYOutlineViewDelegate: NSOutlineView, NSOutlineViewDelegate,NSOutlineViewDataSource{
//....
}    
extension MYOutlineViewDelegate{
    func outlineView(outlineView: NSOutlineView, didClickTableRow item: AnyObject?) {
        //Click stuff
    }

    override func mouseDown(theEvent: NSEvent) {
        let globalLocation:NSPoint  = theEvent.locationInWindow
        let localLocation:NSPoint  = self.convertPoint(globalLocation, fromView: nil)
        let clickedRow:Int = self.rowAtPoint(localLocation)

        super.mouseDown(theEvent)

        if (clickedRow != -1) {
            self.outlineView(self, didClickTableRow: self.itemAtRow(clickedRow))
        }
    }}

Ответ 6

см. уведомление tableViewSelectionIsChanging, вот комментарии от NSTableView.h

/* Необязательно - вызывается, когда выбор будет изменен, но обратите внимание, tableViewSelectionIsChanging: вызывается только тогда, когда события мыши меняют выбор, а не события клавиатуры.  */

Я признаю, что это не самый надежный способ сопоставить щелчки мыши, но это еще одна область для исследования, потому что вас интересуют щелчки мышью.