1

私は C++ アプリを開発しており、内部に WebKit WebView を含む NSWindow を表示する必要があります。ウィンドウの作成と表示を管理する Objective-C クラスをコーディングしましたが、その中に含まれる WebView は表示されません。これが私のコードです。何が間違っているのか、どうすれば修正できるのかについて何か考えはありますか?

以下のコードを $g++ -x Objective-C++ -framework Cocoa -framework WebKit Foo.m main.m -o testでコンパイルしています

フー。

#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

2 に答える 2

4

実行ループを実行する必要があります。ウィンドウを注文して終了すると、まさにそれが起こります。ウィンドウが表示され、(5 秒後に) プログラムが終了します。アプリケーション (作成するが、それ以外の場合は使用しない) にrunを指示することで、実行ループを実行できます。

Cocoa アプリのメインスレッドでは、sleep常に間違った答えです。同じことがそのココアのいとこに+[NSThread sleepUntilDate:]も当てはまり+[NSThread sleepForTimeInterval:]ます。実行ループを使用すると、一定時間実行するように指示できますが、アプリケーションは実行されません。アプリケーションにメッセージを送信する必要がありますがrun、一定の間隔が経過すると終了する機会がありません。

解決策は、ターゲットがアプリケーションで、セレクターが であるNSTimerオブジェクトを最初に作成することです@selector(terminate:)。間隔を 5 秒に設定して、定期的で繰り返しのないものを作成します。(スケジュールされた作成とは、個別にスケジュールする必要がないことを意味します。作成した瞬間から準備が整っています。) 次に、アプリケーションにrunメッセージを送信します。5 秒後、実行ループがタイマーを起動し、アプリケーションに終了を指示します。これは、アプリケーションを 5 秒後に終了させる十分な理由があることを前提としています。

Yuji が指摘したように、最新の Cocoa のすべてのウィンドウは を使用する必要がありますNSBackingStoreBuffered

そして、作成したものをリリースすることを忘れないでください。現在、ビューの場合はそれを忘れています。Cocoaのメモリ管理プログラミング ガイドを参照してください。

これが機能したら、このアプリケーションのより一般的なアーキテクチャに移行することをお勧めします。

  • NSObject のサブクラスを作成し、そのクラスのインスタンスをアプリケーションのデリゲートにします。
  • ウィンドウとその WebView を nib に配置し、アプリ デリゲートにウィンドウ コントローラーを作成させて、その nib のコンテンツを読み込んで所有させます。
  • アプリ デリゲートは、ページを WebView に読み込み、自己終了タイマーを設定する必要もあります。
  • 最後に、アプリケーションのメイン メニュー (メニュー バーの内容) とアプリケーション デリゲートを保持する nib を作成します。Interface Builder には最初の部分のテンプレートがあります。ライブラリから空白のオブジェクトをドラッグし、⌘6 インスペクターでそのクラスを設定し、接続をアプリケーションからオブジェクトにドラッグして、アプリ デリゲート オブジェクトを作成します。main次に、 Xcode のプロジェクト テンプレートが配置する 1 行に減らすことができます: return NSApplicationMain(argc, argv);.

これらすべてを行うことで、Cocoa の理解だけでなく、アプリケーションのメンテナンスにも役立ちますmain

まだ読んでいない場合は、 Cocoa Fundamentals Guideも読む必要があります。

于 2010-08-30T18:28:43.113 に答える
1

それをしないでくださいsleep。GUI が処理されるメイン スレッドの実行を停止します。代わりに、実行ループを実行する必要があります。また、Cocoa 自体をセットアップする必要があります。そのため、呼び出し[[NSApplication sharedApplication] run]て正しく設定し、イベント ループを実行します。

また、バッファリング モード以外のバッキング モードを使用しないでください。他のモードは太古の昔からの名残であり、NSBackingStoreBuffered使用する必要があります。この Apple ドキュメントで説明されているように、非保持モードは Classic Blue Box (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
    

    foo.app次に、Finder からダブルクリックするか./foo、コマンド ラインから呼び出します。

于 2010-08-30T19:00:27.990 に答える