Seite 1 von 1

QApplication: Alternative für den eingebauten Main Loop?

Verfasst: 16. März 2011 14:27
von Subsurf
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:

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;
}
Bei diesem Beispielcode funktioniert das Schließen von QApplication nun, jedoch kommt nach dem Beenden (also nach "Fertig!") noch die Ausgabe
QObject::killTimers: timers cannot be stopped from a different thread (oder so ähnlich)
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?

Verfasst: 16. März 2011 14:34
von franzf
Wäre es nicht einfacher gewesen, erstmal in der Doku nach Spashscreen zu suchen?
Dann findet man "QSplashScreen". In den Detaillierten Beschreibungen etwas weiter unten gibts sogar ein Beispiel, wie man den trotz noch nicht betretener MainLoop anzeigen kann. (*hint* processEvents)

Verfasst: 16. März 2011 14:56
von Subsurf
Oh man... hätte ich gewusst, dass es Qt einem so einfach macht, hätte ich natürlich danach gesucht, aber da ich nicht davon ausging, habe ich es nicht getan.

Danke vielmals, Qt hat soeben einmal mehr gezeigt, dass ich mich für die richtige GUI-Lib entschieden hab :D