2017-09-14 2 views
0

Ich habe gerade etwas QThread-basierten Code geschrieben, der eine große Berechnung ausführt. Um den Fortschritt zu visualisieren, muss ich einen QProgressDialog öffnen. Der Dialog ist anwendungsmodal (mit open()), da ich während der Berechnung keine Änderungen am Hauptfenster zulassen möchte. Der Thread gibt verschiedene Signale aus, die eine zustandsbasierte Kommunikation zwischen GUI und Thread ermöglichen.Modal QProgressDialog :: setValue() verursacht Absturz durch geschachtelte Ereignisschleife

Zwei der vom Worker-Objekt des Threads ausgegebenen Signale sind "Progress" und "Finished". Wenn "Progress" ausgegeben wird, aktualisiere ich den QProgressDialog mit setValue(). Wenn "Fertig" ausgegeben wird, wird der Dialog zerstört.

passiert Folgendes am Ende der Berechnung:

  • "Progress" Ereignis (100%) emittiert wird
  • "Finished" ausgesendet wird direkt nach
  • setValue (100) aufgerufen wird aufgrund "Progress" Ereignis
  • Da der Dialog modal ist, setValue() ruft process()
  • process() tritt die "Finished" -Ereignis
  • Das „Fertig“ Ereignis bewirkt, dass der Dialog in der Mitte von setValue zerstört werden(), die einen Absturz verursacht

QProgressDialog bricht meine Architektur von process() in setValue() aufgerufen wird. Auch meine Codierungskonventionen verbieten die Verwendung verschachtelter Ereignisschleifen (wie in exec() usw.).

Ich habe zwei Fragen:

  1. Warum bedarf es ein modaler Dialog eine verschachtelte Ereignisschleife? Von meinem unerreichbaren Blockieren scheint die Eingabe der Elternfenster dies nicht zu erfordern.

  2. Ist es möglich, QProgressDialog auf eine modale Weise, aber ohne verschachtelte Ereignisschleife zu verwenden?

+0

Wie "zerstöre" der dialog? verwendest du 'deleteLater()'? – Mike

+0

Ihr Fragentitel stimmt nicht mit Ihren tatsächlich nummerierten Fragen überein. Bitte mach, dass sie gleich sind. – xaxxon

+0

@Mike: Ich benutze löschen. Vielleicht ist deleteLater ein Workaround, ich werde das so schnell wie möglich versuchen. – Silicomancer

Antwort

1

sollten Sie deleteLater() verwenden, um Ihre QProgressDialog zu zerstören. Das Ereignis, das Ihr QProgressDialog Objekt löscht, wird innerhalb einer Funktion behandelt, die zu dem Objekt QProgressDialog selbst gehört, das läuft auf die Legitimität des Aufrufs delete this; innerhalb einer C++ - Mitgliedsfunktion hinaus. Weitere Informationen hierzu finden Sie unter this question aus den isocpp C++ - FAQ . Der Kern von ihm ist, dass Sie garantieren sollte, dass Sie keinen Zugriff mehr auf jedes Mitglied des Objekts nach Selbstmord ...

, da Sie diese in der QProgressDialog::setValue() Implementierung nicht garantieren können, Qt, ein Ereignis, das delete s die QProgressBar wie das wird UB beim nächsten Zugriff auf ein beliebiges Mitglied des Objekts (wenn es innerhalb einer Mitgliedsfunktion abgeholt wird) aufrufen. deleteLater wurde speziell entwickelt, um diese Art von Problem zu lösen, da Deferred-Delete-Ereignisse in einer speziellen Weise behandelt werden (sie werden nicht von QCoreApplication::processEvents() abgeholt). Dies bedeutet, dass das QProgressDialog Objekt zerstört wird nach setValue kehrt in die Ereignisschleife zu steuern und nicht in der Mitte setValue der Ausführung ...

immer deleteLater in Situationen wie diese verwendet werden.Wenn Sie innerhalb eines Ereignisses plain delete verwenden, müssen Sie sicherstellen, dass dieses Ereignis beim Ausführen einer Memberfunktion dieses Objekts nicht behandelt wird und dass es nicht ausgeführt wird, wenn ein Signal von diesem Objekt (mit eine direkte signal/slot-verbindung) da immerhin ein signal nur eine member-funktion ist, deren implementierung von Qt's MOC bereitgestellt wird ...

+0

setModal()/show() wird hier nicht funktionieren. Ich benutze bereits open(). QProgressDialog ist speziell, weil es die Ereignisschleife in setValue() sowieso aufruft, egal welche Art von Modalität ich verwende. – Silicomancer

+0

@Silicomancer, Nun, die verschachtelte Ereignisschleife hat nichts mit dem Absturz zu tun, den Sie beschreiben. Wie auch immer, ich habe deine Frage über das Einrichten eines modalen Dialogs ohne verschachtelte Ereignisschleife beantwortet (habe ich deine Frage richtig beantwortet?), Mit 'open()' scheint das auch anders zu sein ... – Mike

+0

Sorry, Mike, aber Ich denke, du hast die Frage nicht beantwortet. Ich weiß, wie man einen modalen Dialog ohne eine Ereignisschleife einrichtet. Meine Frage ist, wie man einen modalen * QProgressDialog * ohne Ereignisschleife einrichtet. Aber ich denke, das ist aufgrund des speziellen Verhaltens von QProgressDialog :: setValue() überhaupt nicht möglich. Vielleicht ist deleteLater ein guter Workaround. Ich werde Feedback geben, nachdem ich es versucht habe. – Silicomancer

Verwandte Themen