2010-12-07 10 views
1

Ich habe eine Linux-C++ - Anwendung mit mehreren Posix-Threads ohne GUI, die in der Lage sein soll, das gelegentliche Cocoa-Steuerelement zu verwenden, nämlich die Datei Upload/Download-Dialoge und die Warnung.Ich kann Cocoa GUI Thread in C++ Applikation mit Objective-C++ GUI nicht finden

Ich bin weit entfernt von einem Experten mit Cocoa, aber war in der Lage, ein paar Objective-C++ Test/Demo-Apps zu bauen, die wie vorgesehen funktionierten.

Jetzt, da ich den Cocoa-Code in meine Anwendung integriert habe, scheint es, dass ich Probleme habe, Dinge im GUI-Hauptthread zu veröffentlichen. Vielleicht habe ich nicht getan, was ich tun musste, um einen zu erstellen, ich bin mir wirklich nicht sicher. Hier ist, was ich in meiner .mm Datei:

#ifdef MACOS 
@interface CocoaInterface : NSObject 
{ 
} 
- (id) init; 
- (void) ShowFileUploadDialog; 
- (void) ShowFileDownloadDialog; 
@end 

@implementation CocoaInterface 
- (id) init 
{ 
    cout << "Creating NSAutoreleasePool" << endl; 
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 
    cout << "Creating NSApplication" << endl; 
    NSApplication* app = [[NSApplication alloc] init]; 
    cout << "Calling NSApplication::finishLaunching" << endl; 
    [app finishLaunching]; 
    [super init]; 
    return self; 
} 

- (void) ShowFileUploadDialog 
{ 
    cout << "Entering ShowFileUploadDialog" << endl; 
    if ([NSThread isMainThread]) 
    { 
     // Show file dialog 
     cout << "Calling NSRunAlertPanel" << endl; 
     NSRunAlertPanel(@"This is a test", @"Does it work?", @"Yes", @"No", @""); 
    } 
    else 
    { 
     //NSRunAlertPanel(@"This is a test", @"Does it work?", @"Yes", @"No", @""); 
     cout << "Redirecting ShowFileUploadDialog call to main thread." << endl; 
     [self performSelectorOnMainThread:@selector(ShowFileUploadDialog) withObject:nil waitUntilDone:YES]; 
    } 
} 

- (void) ShowFileDownloadDialog 
{ 
    cout << "Entering ShowFileDownloadDialog" << endl; 
    if ([NSThread isMainThread]) 
    { 
     // Show file dialog 
     cout << "Calling NSRunAlertPanel" << endl; 
     NSRunAlertPanel(@"This is a test", @"Does it work?", @"Yes", @"No", @""); 
    } 
    else 
    { 
     //NSRunAlertPanel(@"This is a test", @"Does it work?", @"Yes", @"No", @""); 
     cout << "Redirecting ShowFileDownloadDialog call to main thread." << endl; 
     [self performSelectorOnMainThread:@selector(ShowFileDownloadDialog) withObject:nil waitUntilDone:YES]; 
    } 
} 
@end 
#endif 

Ich nenne dies aus dem Code, den ich in den verschiedenen Threads Ich habe die Verarbeitung von eingehenden Netzwerknachrichten:

cout << "Creating CocoaInterface." << endl; 
CocoaInterface* interface = [[CocoaInterface alloc] init]; 
cout << "Calling CocoaInterface::ShowFileDownloadDialog." << endl; 
[interface ShowFileDownloadDialog]; 

Dieser hängt an dem Versuch, die auszuführen Selektor - als ob es den Hauptfaden nie wirklich finden kann. Ein Backtrace in GDB zeigt mir, wie ich für immer auf einen Semaphor warte.

Wenn ich den NSRunAlertPanel-Aufruf vor dem Aufruf performSelectorOnMainThread auskommentiere, erhalte ich einen weißen Block in der Form des Dialogs, aber er zeichnet oder verarbeitet keine Nachrichten, vermutlich weil er nicht im GUI-Hauptthread ist.

Es scheint, dass ich keinen richtigen GUI-Thread habe oder einfach nicht von dort, wo ich bin. Ich vermute, dass ich etwas bei der Initialisierung verpasst habe. Irgendwelche Vorschläge?

Antwort

0

Es stellt sich heraus, was ich brauchte eine Kombination dieser beiden Dinge war:

[NSApplication sharedApplication]; 
[NSApp run]; 

Ich habe von anderen GUI-APIs wie GTK und wxWidgets verdorben worden, so dass

[NSApp terminate: nil]; 

Aufruf hat überraschte mich, indem ich unerwartet die gesamte Anwendung durch einen exit (0) -Aufruf zerstörte und der Rest des main() nie ausführte, aber das ist anscheinend das beabsichtigte Verhalten und ein Thema für einen anderen Tag.

+0

Ja, das ist das beabsichtigte Verhalten. Es steht irgendwo in der Dokumentation. – Yuji

0

Anstatt ein Objekt NSApplication explizit zu erstellen, sollten Sie aufrufen, das die Instanziierung behandelt und die Ereignisschleife für Sie erstellt.

Sie können auch die NSLog(@"Some string") Funktion anstelle all dieser cout s verwenden, wenn Sie möchten.

+0

Vielen Dank, aber es scheint, dass NSApplicationLoad() ist für Carbon-Apps gedacht und es gibt keine Carbon in dieser speziellen Anwendung. –