NSPredicateEditor
的超类NSRuleEditor
公开了一个selectedRowIndexes: IndexSet
属性(以及相应的selectRowIndexes(IndexSet, byExtendingSelection: Bool)
setter(。在该属性上添加一个观察者表明,每当单击谓词编辑器中的一行时,它确实会发生更改。但是,没有视觉指示该行被选中或取消选中。
我想在谓词编辑器中直观地突出显示选定的行,但几乎没有视图绘制方法可以进行子类化或委托方法来实现自定义编辑器的外观。有人能提出一些方法来向用户传达规则编辑器的行已经被选中吗?
在NSPredicateEditorRowTemplate类中,您会发现一个名为templateViews
的属性。如Apple文档中所述,您可以覆盖此属性以返回其他视图。返回一个附加视图,并将其用作所选内容的指示器。
/*返回放置在行中的视图列表。NSPopUpButtons经过特殊处理模板被合并在一起;其他视图按原样添加。除此之外,开发人员还可以重写此项以返回视图,也可以改为返回视图默认视图的。*/
几年前,我定制了NSPredicateEditorRowTemplate来实现星级控制,但必须查找代码以及具体是如何实现的。
希望这能有所帮助。
未文档化,使用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
感谢您迄今为止提供的所有答案。这是我已经决定的,但我担心它的脆弱性。任何改进建议都将不胜感激…
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
}
}
}
}