gpt4 book ai didi

objective-c - 子类化 NSScrollView drawRect : Method

转载 作者:太空狗 更新时间:2023-10-30 04:01:31 27 4
gpt4 key购买 nike

我正在为我的一个应用程序自定义 UI,我的想法是文本区域在未聚焦时最初带有灰色边框,而当它聚焦时,边框变为亮白色。我的应用使用深色主题,对于单行 NSTextField,效果很好。

但是,我遇到了子类 NSTextView 的问题。为了正确地更改边框,我最终不得不实际子类化父 NSScrollView,但我仍然看到奇怪的行为。 (参见下面的屏幕截图。)希望红色框填充整个 ScrollView ,因为这将允许我描边(而不是填充,这只是为了测试)路径,产生一个漂亮的边界。相反,红色框似乎只填充到内部 subview 。

以下代码片段,用于 NSScrollView 子类:

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

NSRect borderRect = self.bounds;
borderRect.origin.y += 1;
borderRect.size.width -= 1;
borderRect.size.height -= 4;

BOOL inFocus = ([[self window] firstResponder] == self);

if (!inFocus) {
inFocus = [self anySubviewHasFocus:self];
}

if (inFocus) {
[[NSColor colorWithDeviceRed:.8 green:.2 blue:0 alpha:1] set];
} else {
[[NSColor colorWithDeviceRed:.1 green:.8 blue:0 alpha:1] set];
}

[NSGraphicsContext saveGraphicsState];
[[NSGraphicsContext currentContext] setShouldAntialias:NO];
[NSBezierPath fillRect:borderRect];
[NSGraphicsContext restoreGraphicsState];

NSLog(@"My bounds: %@", NSStringFromRect(borderRect));
NSLog(@"Super (%@) bounds: %@", [self superview], NSStringFromRect(borderRect));
}

生成如下所示的屏幕截图。此外,请查看日志中的输出,其中建议应填充整个 View 。这是唯一显示的输出,无论内部文本的大小如何。输入回车会增加红色框的高度,但不会产生不同的输出。 (我希望红色框填满整个边界。)

2011-04-08 21:30:29.789 MyApp[6515:903] My bounds: {{0, 1}, {196, 87}}
2011-04-08 21:30:29.789 MyApp[6515:903] Super (<EditTaskView: 0x3a0b150>) bounds: {{0, 1}, {196, 87}}

Drawing Issue

编辑:感谢 Josh Caswell 的回答。请参阅下文了解不专注时和专注时的正确行为。

No Focus

Focus

最佳答案

正如 ughoavgfhw 所指出的,NSScrollView 通常不进行任何绘图,并且可能以这种方式与其 subview 进行奇怪的交互。我建议在您的 TextView 的绘图代码中放置类似以下的内容来绘制您想要的自定义聚焦环*:

// We're going to be modifying the state for this, 
// so allow it to be restored later
[NSGraphicsContext saveGraphicsState];

// Choose the correct color; isFirstResponder is a custom
// ivar set in becomeFirstResponder and resignFirstResponder
if( isFirstResponder && [[self window] isKeyWindow]){
[myFocusedColor set];
}
else {
[myNotFocusedColor set];
}

// Create two rects, one slightly outset from the bounds,
// one slightly inset
NSRect bounds = [self bounds];
NSRect innerRect = NSInsetRect(bounds, 2, 2);
NSRect outerRect = NSMakeRect(bounds.origin.x - 2,
bounds.origin.y - 2,
bounds.size.width + 4,
bounds.size.height + 4);

// Create a bezier path using those two rects; this will
// become the clipping path of the context
NSBezierPath * clipPath = [NSBezierPath bezierPathWithRect:outerRect];
[clipPath appendBezierPath:[NSBezierPath bezierPathWithRect:innerRect]];

// Change the current clipping path of the context to
// the enclosed area of clipPath; "enclosed" defined by
// winding rule. Drawing will be restricted to this area.
// N.B. that the winding rule makes the order that the
// rects were added to the path important.
[clipPath setWindingRule:NSEvenOddWindingRule];
[clipPath setClip];
// Fill the rect; drawing is clipped and the inner rect
// is not drawn in
[[NSBezierPath bezierPathWithRect:outerRect] fill];
[NSGraphicsContext restoreGraphicsState];

这应该是 AppKit 在绘制聚焦环时所做的合理近似。当然,AppKit 允许在 View 边界之外绘制——我不能保证这完全安全,但您似乎可以使用 3 px 的边距。如果需要,您可以将环完全画在边界内。无论如何,真正的聚焦环会在 View 内稍微延伸(2 像素)(就像我在这里所做的那样)。

Apple 文档 Setting the Clipping Region .

编辑:在重新阅读您对该问题的评论后,我意识到我可能已经啰嗦地掩埋了真正的答案。尝试子类化 NSClipView 并为此切换 ScrollView 的剪辑 View ,或者为文档 View 使用自定义 View 。


*: 你也可以把它放在一个自定义 View 子类的绘图代码中,它被设置为 NSScrollView 的文档 View ;那么您的 TextView 可能是它的 subview 。或者替换自定义 NSClipView 子类。

关于objective-c - 子类化 NSScrollView drawRect : Method,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5602350/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com