QApplication: Alternative für den eingebauten Main Loop?
Verfasst: 16. März 2011 14:27
Hallöchen,
ich bin dabei ein größeres Programm zu schreiben, das nach dem Starten erstmal ziemlich viel laden muss und daher für einige Zeit nichts zu sehen ist, sodass man als Nutzer eventuell nicht weiß, ob das Programm nun überhaupt schon läuft.
Deshalb würde ich gerne direkt nach dem Start einen Splashscreen anzeigen, während im Hintergrund geladen wird.
Etwa diesen Programmablauf hatte ich angedacht: Splashscreen-Fenster aufmachen -> alles laden -> Splashscreen-Fenster schließen -> Hauptfenster öffnen.
Problem ist nun die QApplication-Main-Loop, die durch QApplication::exec() gestartet wird. Während dieser Schleife kann ja nichts anderes ausgeführt werden, sodass nach dem nötigen Aufruf von exec() nichts getan werden kann, bis das Fenster vom Nutzer wieder geschlossen wird.
Daher dachte ich, das Ganze multi-threaded zu machen, indem ich das Fenster in einem zweiten Thread öffne, im Hauptthread alles lade und nach dem Laden dann den zweiten Thread wieder kille bzw. das Fenster irgendwie schließe.
Da ich boost::thread für die Threads nutze, fällt das Killen des Threads flach (boost bietet keine Möglichkeit dazu), also versuche ich das Fenster irgendwie zu schließen, aber Qt mag es nicht, Widgets aus einem anderen Thread als dem Thread der QApplication heraus zu schließen.
Mein Ansatz sieht bisher so aus:
Bei diesem Beispielcode funktioniert das Schließen von QApplication nun, jedoch kommt nach dem Beenden (also nach "Fertig!") noch die Ausgabe
ich bin dabei ein größeres Programm zu schreiben, das nach dem Starten erstmal ziemlich viel laden muss und daher für einige Zeit nichts zu sehen ist, sodass man als Nutzer eventuell nicht weiß, ob das Programm nun überhaupt schon läuft.
Deshalb würde ich gerne direkt nach dem Start einen Splashscreen anzeigen, während im Hintergrund geladen wird.
Etwa diesen Programmablauf hatte ich angedacht: Splashscreen-Fenster aufmachen -> alles laden -> Splashscreen-Fenster schließen -> Hauptfenster öffnen.
Problem ist nun die QApplication-Main-Loop, die durch QApplication::exec() gestartet wird. Während dieser Schleife kann ja nichts anderes ausgeführt werden, sodass nach dem nötigen Aufruf von exec() nichts getan werden kann, bis das Fenster vom Nutzer wieder geschlossen wird.
Daher dachte ich, das Ganze multi-threaded zu machen, indem ich das Fenster in einem zweiten Thread öffne, im Hauptthread alles lade und nach dem Laden dann den zweiten Thread wieder kille bzw. das Fenster irgendwie schließe.
Da ich boost::thread für die Threads nutze, fällt das Killen des Threads flach (boost bietet keine Möglichkeit dazu), also versuche ich das Fenster irgendwie zu schließen, aber Qt mag es nicht, Widgets aus einem anderen Thread als dem Thread der QApplication heraus zu schließen.
Mein Ansatz sieht bisher so aus:
Code: Alles auswählen
// stdlib
#include <iostream>
// Qt
#include <QtGui/QApplication>
#include <QtGui/QLabel>
#include <QtGui/QPixmap>
// boost
// Really really really [...] really really important define!:
#define BOOST_THREAD_USE_LIB
#include <boost/thread.hpp>
#include <windows.h>
/**
* Splashscreen-Klasse, die alle nötigen Schritte zum öffnen eines Splashscreens übernimmt.
*/
class Splashscreen
{
private:
QApplication* app;
QLabel* mainWindow;
QPixmap* image;
boost::thread* thread;
// Anwendungsparameter
int argc;
char** argv;
public:
// Konstruktor
Splashscreen(int argc, char** argv)
: app(0),
mainWindow(0),
image(0),
thread(0),
argc(argc),
argv(argv)
{}
// Destruktor
~Splashscreen()
{
close();
}
// Splashscreen öffnen
void open()
{
if(thread == 0)
thread = new boost::thread(&Splashscreen::processingQueue, this);
}
// Splashscreen schließen
void close()
{
if(thread != 0)
{
// QApplication irgendwie beenden :(
app->quit();
delete thread;
}
}
// Thread-Funktion
void processingQueue()
{
app = new QApplication(argc, argv);
image = new QPixmap("D:\\splash.png");
mainWindow = new QLabel();
mainWindow->setPixmap(*image);
mainWindow->show();
app->exec();
}
private:
// Kopierkonstruktor. Sollte niemals aufgerufen werden, aber muss dem Compiler zu liebe implementiert werden.
Splashscreen(Splashscreen const& copy)
{
new (this) Splashscreen(0, 0);
}
};
int main(int argc, char** argv)
{
Splashscreen* mySplash = new Splashscreen(argc, argv);
std::cout << "Gestartet!\n";
Sleep(2500);
std::cout << "Oeffne Splashscreen!\n";
mySplash->open();
Sleep(2500);
std::cout << "Schliesse Splashscreen!\n";
mySplash->close();
Sleep(2500);
std::cout << "Fertig!";
return 0;
}Gibt es eine Möglichkeit, QApplication::exec() selber zu implementieren, um bei jedem Schleifendurchlauf eine "Fenster-Schließen-Flag" abzuprüfen oder könnte man dem Fenster oder der QApplication irgendwie von aussen einen Quit-Befehl senden, damit das ganze richtig "sauber" wird?QObject::killTimers: timers cannot be stopped from a different thread (oder so ähnlich)