0

NSPredicateEditor超类NSRuleEditor公开了一个selectedRowIndexes: IndexSet属性(和相应的selectRowIndexes(IndexSet, byExtendingSelection: Bool)设置器)。在这个属性上添加一个观察者表明,只要单击谓词编辑器中的一行,它就确实发生了变化。但是,没有视觉指示表明该行被选中或取消选中。

我想在我的谓词编辑器中直观地突出显示选定的行,但是几乎没有视图绘制方法可以子类化或委托方法来实现以自定义编辑器的外观。任何人都可以提出某种方式来传达已选择规则编辑器的行吗?

4

3 回答 3

0

无证和hacky,测试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
于 2018-11-03T14:24:41.963 回答
0

感谢到目前为止的所有答案。这是我已经解决的问题,但我担心它的脆弱性。任何改进建议将不胜感激......</p>

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
            }
        }
    }
}
于 2018-11-03T18:38:16.893 回答
0

在 NSPredicateEditorRowTemplate 类中,您将找到一个名为templateViews如 Apple 文档中所述的属性,您可以覆盖它以返回其他视图。返回一个附加视图并将其用作选择的指示器。

/* 返回放置在行中的视图列表。NSPopUpButtons 的特殊处理在于将多个模板的项合并在一起;其他视图按原样添加。开发人员可以覆盖它以返回或代替默认视图的视图。*/

几年前我自定义了 NSPredicateEditorRowTemplate 来实现星级控制,但必须查找代码以及它是如何完成的。

希望这可以帮助。

于 2018-11-03T13:05:50.250 回答