Настройте выделение правой кнопкой мыши на основе представления NSTableView - PullRequest
7 голосов
/ 08 марта 2012

У меня есть основанный на представлении NSTableView с настраиваемым NSTableCellView и настраиваемым NSTableRowView.Я настроил оба этих класса, потому что я хочу изменить внешний вид каждой строки.Реализуя методы [NSTableRowView draw ...], я могу изменить фон, выделение, разделитель и выделение назначения перетаскивания.

Мой вопрос: как изменить выделение, которое появляется, когда строкапри щелчке правой кнопкой мыши появляется меню?

Например, это норма:

И я хочу изменить квадратную подсветку на круглую, напримерэто:

Я мог бы предположить, что это будет сделано в NSTableRowView, вызвав метод вроде drawMenuHighlightInRect: или что-то еще, но я не могу его найти.Кроме того, как класс NSTableRowView может делать это, если я настроил в своем подклассе все методы рисования, и я не вызываю суперкласс?Это нарисовано самой таблицей?

РЕДАКТИРОВАТЬ:

После еще нескольких экспериментов я обнаружил, что круглое выделение может быть достигнуто путем установки представления таблицы в качестве списка источников.Тем не менее, я хочу знать, как настроить его, если это возможно.

Ответы [ 4 ]

9 голосов
/ 03 апреля 2014

Я знаю, что немного опоздал, чтобы предложить какую-либо помощь ОП, но, надеюсь, это может сэкономить некоторым другим людям немного времени.Я вложил в подкласс NSTableRowView, чтобы выделить контекстное меню правой кнопкой мыши (почему у Apple нет открытого метода рисования, чтобы переопределить это, мне не под силу).Вот оно во всей красе:

BSDSourceListRowView.h

#import <Cocoa/Cocoa.h>

@interface BSDSourceListRowView : NSTableRowView

// This needs to be set when a context menu is shown.
@property (nonatomic, assign, getter = isShowingMenu) BOOL showingMenu;

@end

BSDSourceListRowView.m

#import "BSDSourceListRowView.h"

@implementation BSDSourceListRowView

- (void)drawBackgroundInRect:(NSRect)dirtyRect
{
    [super drawBackgroundInRect:dirtyRect];

    // Context menu highlight:
    if ( self.isShowingMenu ) {
        [self drawContextMenuHighlight];
    }
}

- (void)drawContextMenuHighlight
{
    BOOL selected = self.isSelected;
    CGFloat insetY = ( selected ) ? 2.f : 1.f;
    NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:NSInsetRect(self.bounds, 2.f, insetY) xRadius:6.f yRadius:6.f];
    NSColor *fillColor, *strokeColor;

    if ( selected ) {
        fillColor = [NSColor clearColor];
        strokeColor = [NSColor whiteColor];
    } else {
        fillColor = [NSColor colorWithCalibratedRed:95.f/255.f green:159.f/255.f blue:1.f alpha:0.12f];
        strokeColor = [NSColor alternateSelectedControlColor];
    }

    [fillColor setFill];
    [strokeColor setStroke];

    [path setLineWidth:2.f];
    [path fill];
    [path stroke];
}

- (void)drawSelectionInRect:(NSRect)dirtyRect
{
    [super drawSelectionInRect:dirtyRect];
    if ( self.isShowingMenu ) {
        [self drawContextMenuHighlight];
    }
}

- (void)setShowingMenu:(BOOL)showingMenu
{
    if ( showingMenu == _showingMenu )
        return;
    _showingMenu = showingMenu;
    [self setNeedsDisplay:YES];
}

@end

Не стесняйтесь использовать любой из них, изменить любой из них или делать с ним что угодно.Веселитесь!


Обновлено для Swift 3.x:

SourceListRowView.swift

import Cocoa

open class SourceListRowView : NSTableRowView {

    open var isShowingMenu: Bool = false {
        didSet {
            if isShowingMenu != oldValue {
                needsDisplay = true
            }
        }
    }

    override open func drawBackground(in dirtyRect: NSRect) {
        super.drawBackground(in: dirtyRect)
        if isShowingMenu {
            drawContextMenuHighlight()
        }
    }

    override open func drawSelection(in dirtyRect: NSRect) {
        super.drawSelection(in: dirtyRect)
        if isShowingMenu {
            drawContextMenuHighlight()
        }
    }

    private func drawContextMenuHighlight() {

        let insetY: CGFloat = isSelected ? 2 : 1
        let path = NSBezierPath(roundedRect: bounds.insetBy(dx: 2, dy: insetY), xRadius: 6, yRadius: 6)
        let fillColor, strokeColor: NSColor

        if isSelected {
            fillColor = .clear
            strokeColor = .white
        } else {
            fillColor = NSColor(calibratedRed: 95/255, green: 159/255, blue: 1, alpha: 0.12)
            strokeColor = .alternateSelectedControlColor
        }

        fillColor.setFill()
        strokeColor.setStroke()

        path.lineWidth = 2
        path.fill()
        path.stroke()
    }

}

Примечание: Я на самом деле не запускал это, но я уверен, что это должно сработать в Swift.

2 голосов
/ 15 ноября 2018

Это уже немного устарело, но я потратил на это немало времени, поэтому выкладываю свое решение на случай, если оно может кому-нибудь помочь:

  1. В моем случае я хотел полностью удалить строки
  2. Линии не являются кольцами «Фокуса», это то, что Apple делает в недокументированном API
  3. Единственный способ удалить их (без использования недокументированного API) - это открывать NSMenu программно, без Interface Builder.
  4. Для этого мне пришлось кэшировать событие «щелчка правой кнопкой мыши» в TableViewRow, которое имеет некоторую проблему, так как вызывается не всегда, поэтому я тоже имел дело с этой проблемой.

A. Подкласс NSTableView: Переопределение события щелчка правой кнопкой мыши, вычисление местоположения щелчка, чтобы получить правильную строку, и передача его в мой пользовательский NSTableRowView!

class TableView: NSTableView {
    override func rightMouseDown(with event: NSEvent) {
        let location = event.locationInWindow
        let toMyOrigin = self.superview?.convert(location, from: nil)
        let rowIndex = self.row(at: toMyOrigin!)
        if (rowIndex < 0 || self.numberOfRows < rowIndex) {
            return
        }
        if let isRowExists = self.rowView(atRow: rowIndex, makeIfNecessary: false) {
            if let isMyTypeRow = isRowExists as? MyNSTableRowView {
                isMyTypeRow.costumRightMouseDown(with: event)
            }
        }
    }

}

B. Подкласс MyNSTableRowView Представление NSMenu программно

class MyNSTableRowView: NSTableRowView {
    //My custom selection colors, don't have to implement this if you are ok with the default system highlighted background color
    override func drawSelection(in dirtyRect: NSRect) {
        if self.selectionHighlightStyle != .none {
            let selectionRect = NSInsetRect(self.bounds, 0, 0)
            Colors.tabSelectedBackground.setStroke()
            Colors.tabSelectedBackground.setFill()
            let selectionPath = NSBezierPath.init(roundedRect: selectionRect, xRadius: 0, yRadius: 0)
            selectionPath.fill()
            selectionPath.stroke()
        }
    }

    func costumRightMouseDown(with event: NSEvent) {
        let menu = NSMenu.init(title: "Actions:")
        menu.addItem(NSMenuItem.init(title: "Some", action: #selector(foo), keyEquivalent: "a"))
        NSMenu.popUpContextMenu(menu, with: event, for: self)
    }

    @objc func foo() {

    }
}
0 голосов
/ 12 июня 2019

Я согласен с MCMatan, что это не то, что вы можете изменить, изменив любые вызовы на ничью.Поле останется.

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

Я наследую NSTableView и добавляю следующее:

public private(set) var rightClickedRow: Int = -1

override func rightMouseDown(with event: NSEvent)
{
    guard let menu = self.menu else { return }

    let windowClickLocation = event.locationInWindow
    let outlineClickLocation = convert(windowClickLocation, from: nil)
    rightClickedRow = row(at: outlineClickLocation)

    menu.popUp(positioning: nil, at: outlineClickLocation, in: self)
}

override func rightMouseUp(with event: NSEvent) {
    rightClickedRow = -1
}

My rightClickedRow аналогично clickedRow для табличного представления.У меня есть NSViewController, который присматривает за моей таблицей, и он установлен как делегат меню таблицы.Я могу использовать rightClickedRow в вызовах делегатов, таких как menuNeedsUpdate().

0 голосов
/ 08 марта 2012

Я бы посмотрел на NSTableRowView документацию .Это класс, который отвечает за выбор чертежа и перетаскивание отзыва в основанном на виде NSTableView.

...