2010-08-30 38 views
1

我正在开发一个C++应用程序,我需要显示一个NSWindow与WebKit WebView里面。我编写了Objective-C类,它将管理创建和显示窗口,但其中包含的WebView不会显示。这是我的代码。关于什么是错的,以及我如何解决它的任何想法?WebView不显示在NSWindow

我编译下面的代码与 $克++ -x目标C++ -framework可可-framework的WebKit Foo.m的main.m -o测试

foo.h中

#import <Cocoa/Cocoa.h> 
#import <WebKit/WebKit.h> 

@interface Foo :NSObject { 
NSWindow *window; 
WebView *view; 
} 

- (void)displayWindow; 

@end 

Foo.m

#import "Foo.h" 

@implementation Foo 

- (id)init { 

self = [super init]; 

// Window Container 
window = [[NSWindow alloc] initWithContentRect:NSMakeRect(500.0f,500.0f,250.0f,250.0f) 
      styleMask:NSBorderlessWindowMask 
      backing:NSBackingStoreNonretained 
      defer:NO]; 

// WebView 
view = [[WebView alloc] initWithFrame:NSMakeRect(0, 0, 250.0f, 250.0f) 
     frameName:@"Frame" 
     groupName:nil]; 

[[view mainFrame] loadHTMLString:@"<html><head></head><body><h1>Hello</h1></body></html>" 
     baseURL:nil]; 

return self; 
} 

- (void)displayWindow { 
NSLog(@"In Display window"); 

[window setContentView:view]; 
[window setLevel:NSStatusWindowLevel]; 
[window orderFrontRegardless]; 

sleep(5); // leave it up for 5 seconds 

} 

- (void)dealloc { 
[window release]; 
[super dealloc]; 
} 

@end 

的main.m

#import "Foo.h" 

int main() { 

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
[NSApplication sharedApplication]; 

Foo *foo = [[Foo alloc] init]; 
[foo displayWindow]; 
[foo release]; 

[pool release]; 

return 0; 
} 

回答

4

您需要运行运行循环。如果您只是命令窗口然后退出,那就会发生什么情况:将出现窗口,然后(五秒钟后)程序将退出。您可以通过将应用程序(您创建但不使用)运行到run来运行运行循环。

在Cocoa应用程序的主线程中,sleep总是错误的答案。同样的可可堂兄弟,+[NSThread sleepUntilDate:]+[NSThread sleepForTimeInterval:]。运行循环会让你告诉它运行一段固定的时间,但这不会让应用程序运行;您需要发送应用程序run消息,该消息不会在固定时间间隔后退出。

解决方法是首先创建一个对象,其目标是应用程序,其选择器是@selector(terminate:)Create it scheduled并且不重复,间隔设置为5秒。 (创建它预定的意味着你不需要单独安排它 - 它已经准备好从你创建它的那一刻开始。)然后,发送应用程序run消息。五秒钟后,运行循环将触发计时器,这将告诉应用程序自行终止。这假设你实际上有一个很好的理由让你的应用程序在五秒钟后退出。如Yuji所述,现代可可的每个窗口都应该使用NSBackingStoreBuffered

不要忘记释放你创造的东西;您目前在视图中忘记了这一点。请参阅Memory Management Programming Guide for Cocoa

一旦你有这方面的工作,我建议朝着一个更典型的移动架构这种应用:

  • 创建的NSObject的子类,使该类应用程序的委托的一个实例。
  • 将窗口及其WebView放入笔尖,并让应用程序委托创建窗口控制器以加载并拥有该笔尖的内容。
  • 应用程序委托人还应负责将页面加载到WebView中并设置自定义计时器。
  • 最后,创建一个笔尖来保存应用程序的主菜单(菜单栏的内容)和应用程序委托。Interface Builder为第一部分提供了一个模板;您可以通过从库中拖入空白对象,在⌘6检查器上设置其类并将连接从应用程序拖到对象来创建应用程序委托对象。然后,您可以将main减少到Xcode的项目模板放入的单行:return NSApplicationMain(argc, argv);

做这一切将有助于你的可可的理解,以及你的应用程序恶补一切的维护到main不会结垢。

如果还没有,还应该阅读Cocoa Fundamentals Guide

+0

您能否在我的支持商店的评论中增加您的出色答案?我摸了一下头,为什么当我做了明显的事情时他的代码不起作用... – Yuji 2010-08-30 19:04:02

+0

Yuji:很好。完成。 – 2010-08-30 22:13:40

1

不要使它sleep。它停止执行处理GUI的主线程。相反,您需要运行run loop。此外,可可需要设置自己。因此,请致电[[NSApplication sharedApplication] run]将其正确设置并运行事件循环。

此外,不要使用缓冲模式以外的备份模式。其他模式是自古以来的残余,只有NSBackingStoreBuffered应该使用。正如in this Apple document所讨论的那样,非保留模式是支持经典蓝盒子(OS 9虚拟器)的补充,像WebKit这样的新类不能在其中运行。

所以,你需要做的实际上是:

  1. 变化NSBackingStoreNonretainedNSBackingStoreBuffered
  2. 卸下线

    sleep(5); 
    
  3. 添加一行

    [[NSApplication sharedApplication] run]; 
    

    [foo displayWindow]; 
    
  4. 此外,为了对一个应用程序正确地接收从窗口服务器的事件,你需要将它打包到应用程序包中。它编译成一个名为foo二进制文件,并创建以下结构:

    foo.app/ 
    foo.app/Contents/ 
    foo.app/Contents/MacOS/ 
    foo.app/Contents/MacOS/foo <--- this is the executable 
    

    然后你就可以从Finder双击foo.app,或者只是调用命令行./foo