Подсветка выделенных строк в NSPredicateEditor
NSPredicateEditor
суперкласс NSRuleEditor
подвергает selectedRowIndexes: IndexSet
свойство (и соответствующее selectRowIndexes(IndexSet, byExtendingSelection: Bool)
сеттер). Добавление наблюдателя к этому свойству показывает, что оно действительно изменяется при каждом щелчке строки в редакторе предикатов. Тем не менее, нет визуальной индикации того, что строка выбрана или отменена.
Я хотел бы визуально выделить выбранные строки в моем редакторе предикатов, но практически нет методов рисования представления для подкласса или делегирования методов для реализации для настройки внешнего вида редактора. Кто-нибудь может предложить какой-то способ донести до использования, что строки редактора правил были выбраны?
3 ответа
В классе NSPredicateEditorRowTemplate вы найдете свойство с именем templateViews
Как упомянуто в документации от Apple, вы можете переопределить это, чтобы вернуть дополнительные представления. Вернуть дополнительный вид и использовать его в качестве индикатора для выбора.
/ * возвращает список представлений, размещенных в строке. NSPopUpButtons обрабатываются специально тем, что элементы нескольких шаблонов объединяются вместе; другие виды добавляются как есть. Разработчики могут переопределить это, чтобы возвращать представления в дополнение к представлениям по умолчанию или вместо них. */
Я настроил NSPredicateEditorRowTemplate несколько лет назад для реализации элемента управления рейтингом Star, но мне пришлось бы искать код и то, как это было точно сделано.
Надеюсь это поможет.
Спасибо за все ответы до сих пор. На этом я остановился, но меня беспокоит хрупкость. Любые предложения по улучшению будут оценены...
class RowHighlightingRuleEdtitor : NSRuleEditor {
var highlightsSelectedRow: Bool = true
override func didChangeValue(forKey key: String) {
super.didChangeValue(forKey: key)
if key == "selectedRowIndexes" {
// Whenever we change the selection, re-layout the view.
self.needsLayout = true
}
}
override func layout() {
super.layout()
if !highlightsSelectedRow { return }
let selected = self.selectedRowIndexes
// Of all the fragile ways to check if the view is a row, checking the class name is the easiest.
// Possible alternative solution: check for the existence of the add-new-row button.
func viewIsEditorRow(_ view: NSView) -> Bool { return view.className == "NSRuleEditorViewSliceRow" }
// Sorting must be done because the order of the rows does not necessarily correspond to the order of the subviews.
// NSRuleEditorViewSliceRow's superclass NSRuleEditorViewSlice has a rowIndex property, but it is private
// Possible alternative solution: use valueForKey("rowIndex") to get the index
func rowOrder(lhs: NSView, rhs: NSView) -> Bool { return lhs.frame.origin.y < rhs.frame.origin.y }
// subview is NSRuleEditorViewSliceHolder and holds NSBannerView and NSRuleEditorViewSliceRow instances
for (index, rowView) in subviews.flatMap({ $0.subviews }).filter(viewIsEditorRow).sorted(by: rowOrder).enumerated() {
if selected.contains(index) {
// we use *secondary*SelectedControlColor because the rule editor comonent is not actually focusable
rowView.layer?.backgroundColor = NSColor.secondarySelectedControlColor.cgColor
} else {
rowView.layer?.backgroundColor = nil
}
}
}
}
Недокументированный и хакерский, протестирован с NSRuleEditor
: Наблюдайте за изменениями выделения и устанавливайте цвет фона срезов строк. Создать категорию на NSRuleEditorViewSliceRow
и реализовать drawRect:
, Например
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context {
if (context != &myRuleEditorObservingContext)
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
else
{
// backgroundColor is a property or ivar of NSRuleEditorViewSlice and subclass NSRuleEditorViewSliceRow
NSArray *slices = [ruleEditor valueForKey:@"slices"];
[slices makeObjectsPerformSelector:@selector(setBackgroundColor:) withObject:nil];
NSArray *selectedSlices = [slices objectsAtIndexes:[ruleEditor selectedRowIndexes]];
[selectedSlices makeObjectsPerformSelector:@selector(setBackgroundColor:) withObject:[NSColor selectedControlColor]];
}
}
@interface NSRuleEditorViewSliceRow : NSObject
@end
@interface NSRuleEditorViewSliceRow(Draw)
@end
@implementation NSRuleEditorViewSliceRow(Draw)
- (void)drawRect:(NSRect)dirtyRect {
NSColor *aColor = [(id)self backgroundColor];
if (aColor) {
[aColor set];
NSRectFill(dirtyRect);
}
}
@end