QWidget::update() wird nicht ausgeführt

Alles rund um die Programmierung mit Qt
Antworten
sim.on
Beiträge: 4
Registriert: 14. April 2011 11:37

QWidget::update() wird nicht ausgeführt

Beitrag von sim.on »

Hallo!

Ich arbeite an einer relativ umfangreichen Anwendung (Basis ist Qt 4.5.3), die ein Fenster mit einem OpenGL-Bereich (QGLWidget) enthält. Ein Thread ruft in regelmäßigen Abständen die update()-Methode dieses QGLWidgets auf.

Das Problem ist, dass das auch wunderbar eine Weile funktioniert, d.h. die OpenGL-Ansicht wird aktualisiert, aber irgendwann (zwischen ein paar Sekunden und ein paar Minuten) bleibt das Bild stehen.

Der Thread ruft dann immer noch brav update() auf, aber das löst nicht mehr einen Aufruf von paintEvent() aus.
Mit dem Debugger (Visual Studio 2005) habe ich mir angeschaut, was in der update()-Methode passiert. Dort landet er bei

Code: Alles auswählen

tlwExtra->backingStore->markDirty(rgn, this);
und schließlich bei

Code: Alles auswählen

    if (widget->d_func()->paintOnScreen()) {
        if (widget->d_func()->dirty.isEmpty()) {
            widget->d_func()->dirty = QRegion(rect);
            sendUpdateRequest(widget, updateImmediately);
            return;
        } else if (qt_region_strictContains(widget->d_func()->dirty, rect)) {
            if (updateImmediately)
                sendUpdateRequest(widget, updateImmediately);
            return; // Already dirty.
        }

        const bool eventAlreadyPosted = !widget->d_func()->dirty.isEmpty();
        widget->d_func()->dirty += rect;
        if (!eventAlreadyPosted || updateImmediately)
            sendUpdateRequest(widget, updateImmediately);
        return;
    }
paintOnScreen() liefert true und dirty.isEmpty() liefert false. Der else-if-Fall trifft auch nicht zu. Entsprechend der ersten Abfrage liefert nun isEmpty() auch wieder false und somit ist eventAlreadyPosted true, sodass auch das letzte if nicht zutrifft und die Funktion nichts tut und mit return zurückkehrt.

Ich interpretiere den Ablauf so, dass Qt schon weiß, dass bestimmte Teile des Bildschirms neu gezeichnet werden sollen, weil dirty nicht leer ist. Aber warum zeichnet er sie dann nicht neu?
Und warum tut er es anfangs und hört plötzlich damit auf?

Wenn ich das Fenster mal in den Hintergrund lege und dann wieder in den Vordergrung hole, wird es dann aber einmalig neu gezeichnet.
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Re: QWidget::update() wird nicht ausgeführt

Beitrag von solarix »

Hi!
sim.on hat geschrieben:Ein Thread ruft in regelmäßigen Abständen die update()-Methode dieses QGLWidgets auf.
Wie genau machst du das? Ich hoffe doch über ein Signal, welches mit "updateGL" connected ist.. alles andere ist ziemlich sicher illegal...
sim.on
Beiträge: 4
Registriert: 14. April 2011 11:37

Beitrag von sim.on »

Nein, ich rufe direkt die update()-Methode. Denkst du, dass es problematisch ist, weil der Aufruf nicht im GUI-Thread stattfindet? Das sollte doch kein Problem sein, da laut Doku "it schedules a paint event for processing when Qt returns to the main event loop."

Und ich brauche auch das paintEvent() statt nur paintGL(), da ich auch 2D-Sachen in das OpenGL-Fenster zeichne. Das ganze folgt grob dem "Overpainting Example" aus der Qt-Doku. D.h. normalerweise ruft QGLWidget::paintEvent() die Methode paintGL() auf, die das 3D-Zeichnen übernehmen soll. Stattdessen zeichne ich direkt im paintEvent() zuerst den 3D-Teil und dann den 2D-Teil.
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

sim.on hat geschrieben:... Das sollte doch kein Problem sein, da laut Doku "it schedules a paint event for processing when Qt returns to the main event loop."
Und wo steht, dass es thread-safe ist?
sim.on
Beiträge: 4
Registriert: 14. April 2011 11:37

Beitrag von sim.on »

Ich habe es deinem Rat folgend mal nach Signal-Slot-Prinzip umgebaut. update() wird nun in einem Slot im Kontext des GUI-Threads aufgerufen. Trotzdem tritt der Fehler nach einer Weile wieder auf.
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

Sorry.. aber ohne Code (oder noch besser: eine lauffähige Demo) kann man nicht viel dazu sagen..

Entweder du hast noch immer ein Threading-Problem mit dem Update (eine DirectConnection weil der Thread mit moveToThread() nicht zu sich selbst verschoben wurde), oder halt was anderes.

Aber eben: das lässt sich ohne Code kaum erraten.
sim.on
Beiträge: 4
Registriert: 14. April 2011 11:37

Beitrag von sim.on »

Ja, ich sehe ein, dass man ohne Code schlecht helfen kann. Aber leider kann ich aus rechtlichen Gründen keinen Code veröffentlichen.

Ich mache mir immer noch Gedanken, aus welchen Gründen Qt das Neuzeichnen nicht ausführen würde, obwohl der "dirty"-Container aus obigem Code Daten enthält.
Hat jemand eine Idee, wie ich das per Debugger rauskriegen könnte? Also wo im Qt-Code ich ansetzen müsste, um zu sehen, warum er den dirty-Container nicht verarbeitet?

Hat er evtl. keine Zeit dafür? Füllt sich die Qt-Message-Queue immer mehr mit wichtigeren Signalen, sodass die Update/Paint-Nachrichten gar nicht mehr verarbeitet werden?
Kann man irgendwie den Füllstand dieser Message-Queue auslesen?
Aber dann dürfte ja die gesamte GUI nicht mehr reagieren, oder? Das tut sie aber.
astrunck
Beiträge: 6
Registriert: 13. April 2011 16:50

Beitrag von astrunck »

.. weiß nicht, aber vielleicht mal mit 'ner neueren QT-Version probiert? Ich meine da hat sich ja schon einiges getan....
Antworten