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

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

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

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

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


person bright    schedule 01.09.2013    source источник


Ответы (6)


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

Создайте подкласс 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
}
person Peter Lapisu    schedule 29.10.2013
comment
Как обрабатывать события mouseEntered и mouseExit? Любые идеи? - person prabhu; 04.07.2019

Есть простой способ.

Протестировано с 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")
}
person longkai    schedule 30.12.2016
comment
Кажется, лучший ответ. - person Kjuly; 04.04.2017
comment
Только не забудьте также установить tableView.target. - person sam; 02.06.2018
comment
Блестяще! Это действительно лучший ответ - person rmvz3; 20.11.2018
comment
Если вы объявляете метод как @IBAction private func tableRowWasClicked(_ tableView: NSTableView), то в XIB или раскадровке вы можете подключить выход action табличного представления к методу, помимо установки target и action в коде. - person rob mayoff; 23.06.2020
comment
Кажется, это не только хороший ответ, но и то, как он должен работать. Потому что реализация mouseDown и т.п. должна иметь дело с большим количеством координат, которые смещаются, когда таблица помещается внутри NSScrollView. - person Ol Sen; 24.05.2021

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

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

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

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

RequiredRow = row;
RequiredColumn = [tableView clickedColumn];

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

person Suhas Aithal    schedule 05.09.2013
comment
это запускается не только действием пользователя, как указано в вопросе, который я пытаюсь определить, когда щелчок мыши происходит в NSTableView, и когда это происходит, чтобы определить строку и столбец ячейки, по которой щелкнули, но также и каждый время выбор меняется программно - person Peter Lapisu; 29.10.2013
comment
Это также срабатывает, когда пользователь выполняет действия, отличные от щелчка, например нажатие клавиши пробела или буквенная клавиша, когда список находится в фокусе. - person peterflynn; 29.09.2015

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

Добавьте расширение для 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, from: 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.

person Jeff Rafter    schedule 13.02.2017
comment
Работает, но при нажатии на элемент ничего не выбрано - person Maor; 08.07.2017

На всякий случай кто-то искал это в 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))
        }
    }}
person Vladimir Linkevich    schedule 07.05.2015
comment
mouseDown не должно быть в вашем MYOutlineViewDelegate - person LShi; 18.10.2017

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

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

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

person MOK9    schedule 29.11.2014
comment
Я не думаю, что это покрывает это требование из вопроса: мне нужен каждый щелчок мыши, даже если он находится в текущей выбранной строке. - person peterflynn; 29.09.2015