2016-03-18 7 views
0

Ich habe eine Launcher-Anwendung, die fork und exec eine Qt-Anwendung, wenn der Benutzer auf das entsprechende Symbol klickt.Gibt es eine Möglichkeit festzustellen, wann das Hauptfenster der Qt-Anwendung angezeigt wird?

Für visuelle Rückmeldungen möchte ich einen Warte-Cursor anzeigen, wenn der Benutzer ein Symbol auswählt, bis das Hauptfenster der angeforderten Anwendung angezeigt wird.

void RocketLauncher::onItemSelect(QListWidgetItem* item) 
{ 
    QApplication::setOverrideCursor(Qt::WaitCursor); 

    const AppConfig& app = getAppConfig(item); 

    forkAndExec(app.cwd(), app.cmd(), app.args(), app.env()); 

    // TODO: wait until app's main window is being displayed 

    QApplication::restoreOverrideCursor(); 
} 

Das Problem, das ich habe, ist, dass app in meinem Launcher, ich das Kind Prozess pid von fork sofort zurück, aber es dauert noch einige Zeit für das Kind Prozess exec und für seine Hauptfenster erscheint auf dem Bildschirm.

Als solche wird mein Aufruf an QApplication::restoreOverrideCursor() sofort ausgeführt, und es gibt keinen visuellen Hinweis für den Benutzer, dass die Anwendung noch gestartet wird.

Kann ich irgendwie signalisieren, dass das Kind läuft?

Antwort

3

kann ich zwei Möglichkeiten sehen, dies umzusetzen:

  1. Mit expliziter Kommunikation zwischen Prozessen. Die Kind-App kann die Launcher-App nach der Erstellung ihres Hauptfensters informieren, beispielsweise über einen DBus-Aufruf, eine Standardausgabe, einen gemeinsamen Speicher oder einen anderen der vielen verfügbaren IPC-Mechanismen. Es gibt eine startup notification library für X11, die explizite IPC verwendet, indem sie X-Nachrichten, die von KDE und GNOME verwendet werden, weiterleitet.

  2. Je nach Betriebssystem und verwendetem Fenstermanager können Sie den Fenstermanager nach einer Liste geöffneter Fenster fragen und benachrichtigt werden, wenn ein neues Fenster erstellt wird. Ich denke nicht, dass es eine Qt-API dafür gibt, Sie müssten plattformspezifischen Code verwenden. Für X11 würden Sie etwas Ähnliches wie das xwininfo Programm tun. Außerdem gibt es eine LGPL-lizenzierte KDE-Frameworks-API namens KWindowSystem, die ein windowAdded-Signal hat. Ich habe nicht überprüft, auf welchen Plattformen dies tatsächlich implementiert wird, die Dokumentation schlägt mindestens X11 und Mac OS vor.

0

Ich schlage vor, Sie einen Thread starten (mit QtConcurrentRun und behandelt mit QFutureWatcher), die für den Start Kindprozess verantwortlich ist und für das Ende warten GUI angezeigt werden. Dieser Mechanismus kann mithilfe einer Pipe ausgeführt werden, in der Sie Daten von der Stelle im untergeordneten Code senden, von der Sie glauben, dass die GUI angezeigt wird (catch showEvent() oder das Ende des MainWindow-Konstruktors ...). Der Thread im übergeordneten Prozess muss inaktiv bleiben, bis Daten für das Aufwecken in der Pipe empfangen werden.

gibt es eine Menge Beispiel für die Verwendung von Pipe in Linux. Sie können auch Unix-Sockets, Shared Memory oder andere IPCs verwenden oder vielleicht können Sie mit creatin eine Datei in/tmp testen, aber das ist eine schlechte Idee.

Eine weitere einfache Idee ist, mit QProcess und Schreiben von Ihrem neuen Programm eine Zeichenfolge auf der Standardausgabe zu signalisieren Ende der GUI-Anzeige (zu testen ...), um fortzufahren:

bool Class::startExternalProgram(QString _file) 
{ 
    QtConcurrent::run(this, &Class::starting, _file); 
    return true; 
} 

bool Class::starting(QString file) 
{ 
    QProcess *p = new QProcess; 
    params << file; 
    p->start("your program", params); 
    if (!p->waitForStarted(5000)) { 
     p->close(); 
     delete p; 
     crashFinish(1, QProcess::CrashExit); 
     return false; 
    } 
    else { 
     processes.push_back(p); 
     /*to handle crash*/ 
     QObject::connect(p, SIGNAL(finished(int,QProcess::ExitStatus)), 
         this, SLOT(crashFinish(int, QProcess::ExitStatus))); 
     p->waitForReadyRead(600000);/*10mn*/ 
     ... /*handle timeout here*/ 
     return true; 
    } 
} 

void Class::crashFinish(int, QProcess::ExitStatus) { 
    auto p = qobject_cast<QProcess*>(QObject::sender()); 
    ... 
} 
+0

Ich glaube nicht einen Faden Wenn Sie einen Dateideskriptor von einer Pipe haben, können Sie '' QSocketNotifier'' im Hauptthread verwenden, um benachrichtigt zu werden, wenn jemand in die Pipe schreibt. –

+0

Sicher ist es eine gute Lösung, außer dass es notwendig ist, eine Zeitüberschreitung zu verwalten. In diesem Fall müssen Sie einen QTimer erstellen und mit dem Timeout umgehen. Es wird komplexer, wenn das Programm mehrere Programmanfragen gleichzeitig bearbeitet ...? – requinham

+0

Über * "vielleicht können Sie mit Creatin eine Datei in/tmp testen, aber ist eine schlechte Idee" *, es ist nicht sehr elegant, aber ich würde es nicht eine absolut schlechte Idee nennen. Zum einen ist es sehr portabel, einfach zu implementieren und zu verstehen, und leicht zu sehen und zu testen funktioniert alles richtig (obwohl Dateiname die PID des Kindes enthalten sollte, und Eltern sollten auch den Zeitstempel der Datei überprüfen, um sicherzustellen, dass es ist nicht veraltet, und QFileSystemWatcher sollte anstelle der einfachen QTimer-Abfrage verwendet werden, um nach der Datei zu suchen. – hyde

Verwandte Themen