Seite 1 von 2
Programm beenden
Verfasst: 23. März 2008 13:21
von C167
Mein Programm soll sich selbst beenden sobald ein Fehler auftritt. Mein Konstruktor:
Code: Alles auswählen
initDatabase();
createUi();
createActions();
createMenus();
createDocks();
init();
In der Funktion initDatabase() wird eine Datenbankverbindung aufgebaut. Schlaegt das fehl, soll beendet werden. Dazu sieht das Teil so aus:
Code: Alles auswählen
void cdlauncher::initDatabase()
{
db = QSqlDatabase::addDatabase ( "QSQLITE" );
db.setDatabaseName ( QDir::currentPath() +"/../db.dat" );
if (db.open() )
{
QMessageBox::critical ( this, tr ( "Error" ), tr ( "Die zentrale Datenbank konnte nicht gefunden werden.\nUnter Umständen handelt es sich dabei um einen Programmierfehler,\nbitte senden Sie eine E-Mail an den Author." ), QMessageBox::Ok, QMessageBox::NoButton );
QCoreApplication::exit(0);
}
}
Ich provoziere testweise einen Fehler indem ich die Datenbank verschiebe. Die Message-Box geht auch auf, nur wird dannach das Programm nciht beendet, sondern rennt weiter, und die nachfolgenden Klassen, die auf die Datenbank zugreifen, geben eine Menge Fehler von sich, bis das Programm einen SegFault bekommt und terminiert wird. Der eventLoop wurde in der main-Methode per
gestartet, also sollte die Sache sich beenden. Warum tut das nicht wie es tun soll?
C167
Verfasst: 23. März 2008 19:08
von Christian81
Doku lesen ->
http://doc.trolltech.com/4.3/qcoreapplication.html#exit
After this function has been called, the application leaves the main event loop and returns from the call to exec(). The exec() function returns returnCode. If the event loop is not running, this function does nothing.
Da steht nichts von 'exits immediatelly' ...
Verfasst: 23. März 2008 19:10
von Der Neue
Hallo
Das müsste eigentlich schon funktionieren, ist zumindest bei mir der Fall.
Der Konstruktor wird sicher erst nach app.exec() ausgeführt? Nicht, dass du das Objekt schon vorher erstellst, dann hat das natürlich keine Wirkung.
mfg
Sorry, hat sich dann wohl erledigt.
Verfasst: 24. März 2008 12:10
von C167
Da steht nichts von 'exits immediatelly' ...
Ich war eigentlich der Meinung, dass bei Aufruf wie es da steht der Main EventLoop verlassen wird und das app-Objekt bei app.exec() den eingegebenen Return-Wert an den return-Befehl aus der Main-Methode weitergibt und somit das ganze beendet.
Ausserdem wir der Konstruktor _or_ app.exec aufgerufen
Code: Alles auswählen
int main ( int argc, char *argv[] )
{
QApplication app ( argc, argv );
qDebug() << QCoreApplication::arguments();
launcher * cdl = new launcher();
cdl->show();
return app.exec();
}
wie es bisher in fast allen Beispielen und Anleitungen getan wurde.
Wie kann ich das Programm also zuverlaessig wegballern?
Verfasst: 24. März 2008 17:10
von Christian81
'Der Neue' hat doch schon gesagt was Du falsch machst...
C-funktion 'exit()' gibts ja auch noch...
Verfasst: 24. März 2008 18:58
von C167
oehm, naja okay, ich moechte so weit wie moeglich nur Qt-Funktionen verwenden.
Nun braeuchte ich eine Erklaerung, was
Der Konstruktor wird sicher erst nach app.exec() ausgeführt? Nicht, dass du das Objekt schon vorher erstellst, dann hat das natürlich keine Wirkung.
zu bedeuten hat, denn app.exec() blockiert das ganze, und der code nach app.exec() wird erst ausgefuehrt, wenn app.exec() beendet ist.
ausserdem steht in der doku:
int QApplication::exec () [static]
Enters the main event loop and waits until exit() is called, then returns the value that was set to exit() (which is 0 if exit() is called via quit()).
Genau das mache ich ja, ich lege mein Objekt an und starte den event-loop. der soll dann oer QCoreApplication::exit(1); verlassen werden.
Verfasst: 24. März 2008 19:56
von Der Neue
Ja, alles recht und gut. Aber dein Konstruktor wird ja schon ausgeführt bevor du app.exec() aufrufst, weil du ja dein launcher-Objekt auch schon vorher erstellst. Das heißt dann, dass QCoreApplication::exit(1) aufgerufen wird, obwohl noch überhaupt keine Nachrichtenschleife läuft, weil eben app.exec() vorher nicht aufgerufen wurde.
Verfasst: 24. März 2008 20:08
von C167
Code: Alles auswählen
int ret = app.exec();
launcher * cdl = new launcher();
cdl->show();
return ret;
das qDebug vor alledem geht, aber nach der app.exec-Zeile passiert erwartungsgemaess garnichtsmehr
Verfasst: 24. März 2008 20:13
von Christian81
Nimm exit() !!!
Verfasst: 24. März 2008 20:55
von C167
exit schoen und gut, damit funktioniers, danke soweit. Nur wie funktionieren dann die Qt-Funktionen dazu?
Verfasst: 24. März 2008 20:59
von Christian81
Ich gebs auf...
Verfasst: 24. März 2008 21:55
von C167
gebt mir doch bitte einfach mal ein Beispiel mit einer main-Funktion und einer von QMainWindow abgeleiteten Klasse.
app.exec() blokiert in jedem Fall die Funktion, die es aufruft, welche dann nur fertig abgearbeitet hat wenn app.exec() per QCoreApplication::exit(int) abgebrochen wird oder das ding close aufruft. Ich hab bis jetzt in keinem meiner Buecher ein Beispiel gesehen, bei dem main als letztes etwas anderes enthielt als return app.exec();
Verfasst: 26. März 2008 14:54
von C167
die einzige Moeglichkeit, die mir einfaellt ist, die ganze intialisierung zu machen, sobald der user irgendwas macht. Die Initialisierung erfolgt bei mir im konstruktor, und mir ist momentan keine Moeglichkeit bekannt, sie erst auszufuehren wenn der event loop am laufen ist.
Verfasst: 26. März 2008 15:53
von solarix
Aus einem Konstruktor würde ich keine solchen Dinge machen.. zum einen ist das saubere runterfahren da so ne Sache (Objekt wird gerade erstellt), zum anderen sind da komplexere Abläufe nicht sehr schoen umsetzbar (Exceptions, virtuelle Methoden usw.).
Ausserdem ist das Modul nicht sehr gut wiederverwendbar (plötzlicher exit..).
Ich würde es daher erst nach dem Erstellen initialisieren:
Wenn du den exit doch in deiner Klasse aufrufen möchtest, würde ich dies in Form eines "lazy loads" implementieren. Also erst bei der ersten Verwendung der Daten (z.B. wenn Model abgefragt wird oder View neu gezeichnet wird etc.) die Datenbank abfragen und gegebenfalls die Applikation beenden.
Verfasst: 27. März 2008 00:55
von C167
problem ist, dass, nachdem die Grundoberflaeche angelegt wird, sofort Daten aus der Datenbank kommen _muessen_ und ich darum nicht viele Moeglichkeiten hab, ohne DB etwas zu machen, da die ersten Ansichten schon mit Fehlern um sich werfen und irgendwann SegFault'en
Mit Exceptions gebe ich mich garnicht ab, wenn was schief laeuft, wird knallhart teminiert. Die Anwendung nimmt vom Benutzer ausser dem Druecken auf Knoepfe und Listen keine Eingaben entgegen, und wenn was schief laeuft ist die Sicherheit der Daten gefaerdet. Virtuelle Methoden... kenn ich (noch) nicht, mal suchen...
Nun stellt sich da aber fuer mich eine generelle Designfrage: Wie soll denn eine Initialisierung aussehen? in Main wird ein Objekt einer Klasse angelegt und dessen Konstruktor aufgerufen. der baut die Oberflaeche auf und sobald show() zurueckkehrt wird app.exec() aufgerufen. Ab da ist es nicht mehr Moeglich, der Hauptklasse von "unten" her aus der main heraus irgendetwas zu sagen. Einzige Moeglichkeit die mir einfaellt, ist die:
Code: Alles auswählen
int main(void)
{
// ...
launcher *cdl = new launcher();
cdl->show();
while (true)
{
if (cdl->isReady())
return app.exec();
}
}
}
was nicht sehr schoen aussieht