【问题标题】:NSView containing NSOpenGLView doesn't redraw after a subview is removed删除子视图后,包含 NSOpenGLView 的 NSView 不会重绘
【发布时间】:2014-05-30 00:03:55
【问题描述】:

我有一个 Mac OS X (10.9) 应用程序,我的主 NSWindow 的 contentView 属性带有一个自定义 NSView。自定义视图唯一要做的就是覆盖drawRect:,使其透明。透明度是必需的,以便我的 NSOpenGLView 可见(见下文):

/* Transparent NSView Subclass */
- (void)drawRect:(NSRect)dirtyRect
{
  NSLog(@"Drawing Rect");
  [[NSColor clearColor] set];
  NSRectFillUsingOperation(dirtyRect, NSCompositeClear);
}

contentView 有一个 NSOpenGLView 作为子视图,其表面顺序设置为 -1(它在主 NSWindow 的“下方”,也是透明的):

/* NSOpenGLView subclass: */
GLint order = -1;
[self.openGLContext setValues:&order forParameter:NSOpenGLCPSurfaceOrder];

然后我实例化一个 WebView 并将其放置为这个自定义视图的子视图:

_webview = [[WebView alloc] initWithFrame:frame];
[_webview setMaintainsBackForwardList:NO];
[_webview setTranslatesAutoresizingMaskIntoConstraints:NO];
[_webview setDrawsBackground:NO];
[_window.contentView addSubview:_webview];

WebView 是窗口中的一个小框(在 NSOpenGLView 的顶部),用于登录服务。一旦登录发生,它应该会消失,只显示 NSOpenGLView。

问题是:当我调用[_webview removeFromSuperview]; 时,contentView 不会重绘;因此,WebView 仍然在屏幕上绘制(尽管不响应鼠标或键盘)。如果我使用鼠标调整所有内容所在的窗口大小,contentView 会重绘(我在日志中看到消息)并且 WebView 的内容会消失。 另外,如果我不将 NSOpenGLView 添加为子视图,WebView 会按原样消失。

在删除子视图后,contentView 不应该触发drawRect 吗?即使我在删除 WebView 后使用setNeedsDisplay:setNeedsLayout:contentView 仍然没有重绘。

【问题讨论】:

    标签: objective-c macos cocoa nsview nsopenglview


    【解决方案1】:

    Apple 最近的建议是使用 Core Animation 层将普通视图置于 OpenGL 视图之上。

    我怀疑内容视图已经重绘了自己。它画得很清楚。您看到的是它背后的 OpenGL 表面。 OpenGL 表面的近乎原始 VRAM 特性可能意味着在其上绘制的 Web 视图实际上修改了表面的内容。因此,我建议您强制 OpenGL 视图重绘自身。如果它吸引到它的-drawRect:,那么它应该足以发送-setNeedsDisplay:。如果你在-drawRect: 之外通过手动将上下文设置为当前,发出渲染命令,然后调用-flushBuffer 进行渲染,那么你需要这样做。

    【讨论】:

    • 谢谢肯。要设置 CA 层的使用,我是否仍将 NSOpenGLView 子类化并使用setNeedsLayer:,还是需要将 NSView 子类化并手动设置 NSOpenGLContext?此外,在 CALayer 的情况下,是否有必要使用 NSOpenGLCPSurfaceOpacity 设置为 -1 或者图层是否不需要在窗口后面发送上下文?我在openGLContext 上尝试了手动flushBuffer 没有运气,我也没有运气将绘图移到drawRect:。在这两种情况下,我都使用CADisplayLink 进行计时。您可以向我指出有关为此使用 CA 层的任何好的文档吗?
    • Apple 提供了示例代码LayerBackedOpenGLView,用于演示。您所要做的就是使NSOpenGLView 支持层(在IB 中或使用setWantsLayer:YES),然后您可以添加子视图。不使用透明视图或窗口或将上下文设置在窗口后面。 Web 视图应该是 GL 视图的子视图,而不是兄弟视图。
    • 谢谢。我走那条路并将我的渲染代码移动到drawRect:,因为所有东西都必须在那里和主线程上绘制。这比在CVDisplayLink 线程上的后台绘图使用更多的 CPU(8% 对 2%)。有什么办法吗?此外,我的纹理现在是黑色的 - 切换 setWantsLayer:NO 会显示它们,但 setWantsLayer:YES 它们是黑色的。我从 Apple 的示例项目中复制了 NSOpenGLPixelFormat,但没有运气。有什么想法吗?
    • 在黑色纹理上,我发现在使用setWantsLayer:YES 时,在程序开始时设置了一些纹理时,实际上并没有设置上下文。是否有一些事件可以与确定上下文何时出现有关?最后,discussion here 提到支持图层的 NSOpenGLViews 已过时,并建议手动设置图层。我可能会尝试这条路线,尽管要到达那里需要更多的重构。
    • 覆盖 -prepareOpenGL 以在设置上下文后执行工作。
    猜你喜欢
    • 2013-02-08
    • 1970-01-01
    • 2013-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多