Qt Programm im Konstrukto beenden

Alles rund um die Programmierung mit Qt
Antworten
f.o.g.
Beiträge: 25
Registriert: 25. September 2009 10:53

Qt Programm im Konstrukto beenden

Beitrag von f.o.g. »

Hey mal ne Frage. Wie kann man ein bereits im Konstruktor das öffnen des Programms verhindern. Das Problem ist folgendes. Während des Konstruktors hole ich mir mittels DLL Funktionen einige Callback Pointer von der DLL. Geht dabei etwas schief möchte ich, dass eine Messagebox erscheint und sich das Programm anschließen beendet. Die Messagebox stellt kein Problem dar aber bei close passiert nix :(
Danke für eure Hilfe

Code: Alles auswählen

if (!foobar)
{
	QMessageBox::warning(this,"Fehler","Konnte Pointer nicht Initialisieren");
	close();
}
Exasperation
Beiträge: 186
Registriert: 11. März 2009 18:00
Wohnort: VS

Beitrag von Exasperation »

Code: Alles auswählen

if (!foobar)
{
   QMessageBox::warning(this,"Fehler","Konnte Pointer nicht initialisieren");
   exit(1);
} 
exit( int _Code )
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

QApplication::exit()
Aber ich würde das in einer initialize() - Funktion machen.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Es ist besser, du verwendest

Code: Alles auswählen

qApp->quit();
Dann hast du noch die Chance auf [signal] QCoreApplication::aboutToQuit() zu reagieren. Auch die eventloop wird dadurch korrekt terminiert.
f.o.g.
Beiträge: 25
Registriert: 25. September 2009 10:53

Beitrag von f.o.g. »

danke das ging ja echt fix. ich hab jetzt folgende Lösung

Code: Alles auswählen

QMetaObject::invokeMethod(this, "close", Qt::QueuedConnection);
das funktioniert perfekt. Die exit Methode endet in einer Zugriffsverletzung. Die Lösung von franzf hat leider nicht funktioniert. Programm bleibt offen (schade)
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

OK, etwas drüber gegrübelt. Das close() funktioniert nicht, weil dein Fenster im Konstruktor noch nicht sichtbar ist. Die Aufrufreihenfolge ist dann [Konstruktor:close()]->show() -> tüdelü :P
Du verzögerst jetzt das close(), indem du über die QueuedConnection erst den folgenden Lauf der EventLoop abwartest. Bis dahin ist das Fenster konstruiert und auch sichtbar -> alles bestens :P
Warum quit/exit nicht gehen - hmm. Müsste ich schauen. SegFault vllt. wegen Destruktoraufruf im Konstruktor - müsste man mit debugger reingehen.

Die sauberste Lösung wäre eine Exception. Wenn dein Objekt die Symbole aus der DLL für seine Existenz braucht, ist ein nicht auffindbares Symbol eine Ausnahme, die das Objekt nutzlos, kaputt, ... macht. Für sowas wirft man im Konstruktor eine passende Exception. Die kannst du abfangen und danach deine MessageBox aufrufen. Aber bitte dann nicht wieder im Konstruktor einer anderen Klasse, sondern in einer Funktion.
Eine initialize()-Methode wäre auch denkbar, die VOR dem Erzeugen einer Instanz deiner Klasse aufgerufen wird (wie von Christian vorgeschlagen). Problem hier könnte aber sein, dass du mehrere Klassen mit unterschiedlichen Anforderungen an Symbole hat. Dann müsstest du eine zentrale initialize()-Methode ständig anpassen. Vergisst du das -> Bumm!
Wenn du das initialize als Memberfunktion implementierst, die NACH dem Erstellen eines Objekts aufgerufen werden MUSS, solltest du das über eine factory-Methode realisieren, damit man auch ja nicht das initialisieren vergisst:

Code: Alles auswählen

class Klasse {
fkt* sym;
// private Konstruktor
Klasse() {
    // allgemeines BLABLA
}
bool initialize() {
    sym = DllLoader::getSym("symbol_name");
    return sym;
}
     
public:
    static Klasse* get() {
        Klasse* k = new Klasse;
        if(!k->initialize()) {
            delete k;
            return 0;
        }
        return k;
    }
};

int main() {
    // allgemeines Blabla
    Klasse* k = Klasse::get();
    if( !k ) {
        // messagebox aufklappern
        QApplication::exit();
    }
    // usw.
}
f.o.g.
Beiträge: 25
Registriert: 25. September 2009 10:53

Beitrag von f.o.g. »

und was genau spricht jetzt gegen meine Lösung?
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

f.o.g. hat geschrieben:und was genau spricht jetzt gegen meine Lösung?
Sie ist nicht wirklich sauber, da es die EventLoop für etwas nutzt, was du mit normalen C++-Programmierparadigmen besser lösen kannst, die dann auch immer zuverlässig funktionieren. Bei deiner Lösung musst du nur auf die Idee kommen, das closeEvent() zu implementieren, und event->ignore() aufzurufen, und das close() schließt das Widget nicht und beendet auch nicht das Programm. Viel Spaß beim Fehlersuchen :P

Es kann auch Probleme geben, denn ein close() schließt nur das Fenster, falls das Flag WA_DeleteOnClose gesetzt ist. Und dein Programm bricht eben doch nicht ab, wenn nur das eine Widget sich beendet. Wenn das das MainWindow ist, und keine anderen unabhängen QWidget rumfliegen bedeutet das auch das Ende für dein Programm.

Dann ist ein im Konstruktor vorbereiteter Selbstzerstörungsmechanismus für den Verwender der Klasse absolut undurchsichtig, denn er erstellt ein Objekt, erkennt nicht ob die Erstellung funktioniert hat und verlässt sich während dem Programmverlauf auf dessen Existenz. Und plötzlich wird das Ding zerstört :/
Lass z.B. in der EventQueue auch ein Event liegen, das das erstellende Objekt dazu veranlasst, auf dein AutoDelete-Objekt zuzugreifen. Dann nimm auch an, dass dein Widget das close() vor dem anderen Event bekommt. Das bedeutet SegFault :P da du nach dem Zerstören in dem noch ausstehenden Event auf das zerstörte Objekt zugreifen willst - auf NULL prüfen geht auch nicht, da nach delete eben der Pointer NICHT auf NULL gesetzt wird, sondern auf den deinitialisierten Speicherbereich zeigt.

Ich weiß, etwas verworren, aber so ist das, die Fallstricke sind bei deiner Methode so diffiziel und vielfältig, dass es beim Drüberstolpern schwer ist sie auszumachen.
Bei den beiden oben erwähnten Lösungen (Exception im Konstruktor, Factory-Methode die bei Fehler NULL zurückgibt) existieren diese Fallstricke eben nicht.
padreigh
Beiträge: 340
Registriert: 13. Mai 2010 10:06

Beitrag von padreigh »

Code: Alles auswählen

Konstructor () 
{
    // konstruktor zeug



    if (willsDochNicht)
        QTimer::singleShot(1,qApp,SLOT(close())); // ruft den Slot 1ms nach start der EventQueue auf - dann ist alles existent und wird gleich wieder beendet ;) da gibts auch ne closeAllSubwindows oder so falls mehrfenster allplikation
}
aber vielleicht mit den selben Fallstricken behaftet die franz schon erwähnte
Patrick (QtCreator 1.3.1, Qt 4.6.3)
---
template = subdirs
Antworten