2010-08-30 41 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