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>

задайте разширения делегат на 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 на отговора на Peter Lapisu:

Добавете разширение за 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

можете ли да покажете кода си какво сте опитали
person MOK9    schedule 29.11.2014
comment
Не мисля, че това покрива това изискване от въпроса: Искам всяко щракване с мишката, дори и да е на текущо избрания ред. - person peterflynn; 29.09.2015