Fenster wirklich neu zeichnen



  • @Th69
    Hier noch de eine Fktn von meinem Vorgänger:

    void UpdateCmdUI(BOOL bFromThread)
    {
    	if(bFromThread) // 20100520	RH
    		theApp.m_pFrame->SendMessage(WM_COMMAND,ID_UPDATE_TOOLBAR);
    
    //	else
    //		theApp.m_pFrame->m_wndCommandBar.OnUpdateCmdUI(theApp.m_pFrame,TRUE);
    }
    
    


  • Wie ich schon geschrieben habe, kommentier zur Fehlersuche mal alles aus und nach- und nach wieder ein. Oder lass alles auskommentiert und zeichne ein paar Elemente selbst um zu gucken, ob das funktioniert.



  • @DocShoe
    Die "brushes", etc, sind lokal definiert.
    Am Ende der "DrawMainView(..)" erfolgt:

    	if(pOldFont)
    		pDC->SelectObject(pOldFont);
    	delete pCompatibleDC;
    	if(pOldBrush)
    		pDC->SelectObject(pOldBrush);
    	if(CheckSprache(pAnlage,4))
    		CreateStdFont(FALSE);
    
    


  • @DocShoe
    Zwischen meinem ersten Versuch, der funktionierte, habe ich nichts an dem Teil des Quellcodes geändert.
    Aber ich versuche auch mal das auskommentieren und auch die alte Version, die funktionierte.



  • @elmut19
    Ja wenn nix geändert worden ist müssen es ja Neutrinoeinschläge in der CPU oder GPU sein.



  • @DocShoe
    oder Windows Update ...
    ... Typische Aussage, ich weiss auch: "Wir haben nix geändert ..."
    Klingt schon lustig.

    Aber eine ältere Version (leider nicht die, die erste Implementierung dazu hatte) funktioniert auch nicht mehr.



  • Lass doch mal die KI drüber schauen. In Syntax-Fragen ist sie gut.


  • Mod

    1. HeapCompact hat nicht im OnDraw zu tun.
    2. OnDraw wird im Kontext von einer WM_PAINT Nachricht versendet.
      Entsprechend wird diese Nachricht nur erzeugt wenn:
      a. das Fenster/der Auschnitt sichtbar ist
      b. der Ausschnitt auch aktualisiert werden muss
    3. In OnDraw hat ein UpdateWindow/RedrawWindow/InvalidateRect nichts zu suchen. Denn dies führt evtl. zu rekursiven aufrufen.
    4. In einem OnDraw musst Du alle Bereiche auch neu zeichnen die betroffen sind.
    5. Nach dem OnDraw / WM_PAINT werden alle Fenster/Bereiche validiert, das heißt sie bekommen das Flag "aktuell"
    6. Durch ein InvalidateRect bekommt ein Bereich/Fenster das Flag "nicht aktuell"
    7. Ein UpdateWidnow/RedrawWindow wird alle Bereiche aktualisieren, die als "nicht aktuell" markiert sind.


  • @Erhard-Henkes
    Hatte ich auch schon mal gemacht (anderer Fall)
    Hat erkannt, was ich tun wollte. Aber nicht den Fehler gefunden.



  • @elmut19 sagte in Fenster wirklich neu zeichnen:

    oder Windows Update ...

    Bitte bleibt doch mal sachlich. Das Problem ist die WinAPI mit ihren vielen Seiteneffekten. Erst neulich hat Dr. Memory z.B. bei mir einen Fehler im Subclassing entdeckt. Und so wie es aussieht, verursachte dieser Fehler nur in 0,001% aller Fälle einen Absturz.

    Ein paar weitere Punkte:

    • DIe Anweisung delete pCompatibleDC; finde ich etwas merkwürdig und sollte man überprüfen.
    • Ferner würde ich den folgenden Code prüfen:
    if(bFromThread) // 20100520	RH
    		theApp.m_pFrame->SendMessage(WM_COMMAND,ID_UPDATE_TOOLBAR);
    

    Wenn der Aufruf hier durch einen Thread erfolgte, so sendest du eine WM_COMMAND Nachricht an m_pFrame. Oder genauer gesagt, fügst du eine WM_COMMAND Nachricht in die Message Queue von m_pFrame ein und wartest bis diese bearbeitet wurde.

    -> Was passiert wenn du stattdessen PostMessage()WM_COMMAND` aufrufst?

    • BTW: EIn Klassiker beim Threading sind Synchronisationsfehler. Welche Thread Safety benötigst du? Und wie Thread Safe ist dein Code?


  • Lass da generell mal cppcheck drüberlaufen.



  • @Martin-Richter
    Tja, wo kann ich das "Invalidate.."-Zeugs dann hintun?
    Meine "DrawMainView(..)" ist ja praktisch Teil der "OnDraw()".
    Und dort wird eigentlich alles neu gezeichnet.
    Aber nicht nur das Neue, sondern auch das Alte. Scheint zumindest so.
    Andererseits werden in dem View zyklisch Texte neu ausgegeben, die sich ändern.
    Diese werden nicht übereinander geschrieben.

    Das mit "rekursive Aufrufe" habe ich ja erfolgreich unterbunden.
    Was mein Vorgänger mit seinem "Heap"-Zeugs vorhatte, weiss ich nicht.
    Es hat seit 20? Jahren nicht gestört.


  • Mod

    Invalidate brauchst Du gar nicht. Außer Du willst das neu Zeichnen erzwingen.
    Wenn Dinge übereinander gezeichnet werden, dann wird evlt. der Hintergrund nicht neu gezeichnet. Also das alte Zeugs überschrieben.
    Du musst nichts "unterbinden", sondern es unterlassen.
    Wenn es nicht stört heißt es nicht dass es richtig ist.



  • @elmut19 sagte in Fenster wirklich neu zeichnen:

    @Martin-Richter
    Tja, wo kann ich das "Invalidate.."-Zeugs dann hintun?

    An die Stelle, an der die Konfiguration geändert worden ist. Am Besten entkoppelst du das auch noch und löst das per Observer Pattern:

    (Pseudocode)
    void SomeClass::set_configuration( MyConfigurationData const& cfg )
    {
       // Beim Setzen einer neuen Konfiguration wird ein Ereignis ausgelöst, das an alle angemeldeten Subscriber abgesetzt wird.
       Configuration_ = cfg;
       OnConfigurationChanged.fire( );
    }
    
    CViewTitanCe.cpp
    CViewTitanCe::CViewTitanCe()
    {
       // Subscriber anmelden
       instance_of_some_class().OnConfigurationChanged.subscribe( OnConfigurationChanged );
    }
    
    CViewTitanCe::~CViewTitanCe()
    {
       // Subscriber abmelden
       instance_of_some_class().OnConfigurationChanged.unsubscribe( OnConfigurationChanged );
    }
    
    void CViewTitanCe::OnConfigurationChanged()
    {
       // Callback für Konfigurationsänderung: Neuzeichnen anstossen
       Invalidate();
    }
    

    Leider gibt's im Standard C++ keine Publisher/Subscriber Unterstützung, da musst du dir was eigenes basteln. Für den Anfang reicht da vielleicht auch schon ein Funktionszeiger oder std::function.



  • @Martin-Richter
    Ja, ich wollte ja das Neuzeichnen erzwingen.
    Aber was läuft dann schief?

    Ich muss noch Einiges Überdenken.

    Danke jedenfalls erstmal Euch allen



  • Wie schon geschrieben, mußt du das Neuzeichnen außerhalb des Zeichenvorgangs anstoßen.

    Für das Löschen des Hintergrunds ist normalerweise die Nachricht WM_ERASEBKGND zuständig. Kannst ja mal schauen, ob dies in eurem Projekt verwendet wird (falls nicht, sollte es automatisch so funktionieren) - evtl. auch mal den Parameter fErase (wie im Link beschrieben) überprüfen.



  • @Martin-Richter @Th69 @DocShoe
    Danke für Eure Hilfe und für den Beispielcode.
    Habe wieder was dazugelernt.

    Ich habe jetzt jedenfalls verstanden und akzeptiert, dass das "Invalidate.."-Zeug nicht in diese "Draw()" oder "OnDraw()" Funktionen gehört.
    Vor drei Wochen, als ich das implementiert habe, war zumindest mein Eindruck, dass das "Invalidate" eine Aktion ausgelöst hatte.
    Nun scheint es das nichtmehr zu tun. Wie auch immer ... vielleicht nicht alle Fälle getestet ....

    Inzwischen habe ich auch herausgefunden, dass, auch ohne "Invalidate", etc., ein Neuzeichnen stattfindet.
    Somit lag der Fehler in meinem Algorithmus, der in einem bestimmten Fall die erste Zeile falsch berechnete.

    Also vielen Dank nochmals an alle.



  • @elmut19

    Ja, man muss verstehen, wie Windows intern Fenster und deren Zustände verwaltet (die MFC ist auch nur ein Wrapper um die WINAPI). Das Neuzeichnen passiert nur auf eine Reaktion auf eine WM_PAINT Nachricht, und da gibt es verschiedene Möglichkeiten, diese Nachricht an ein Fenster zu schicken:

    • Kombination aus InvalidateRect und UpdateWindow: Mit InvalidateRect werden Teile des Fenster als ungültig markiert, UpdateWindow fasst die ungültigen Bereiche zusammen und schickt die WM_PAINT Nachricht an das Fenster. Es wird nicht auf die Bearbeitung der WM_PAINT Nachricht gewartet, das Programm läuft nach UpdateWindow weiter, ohne dass neu gezeichnet worden ist. Das Neuzeichnen passiert dann irgendwann, wenn kein User Code mehr ausgeführt wird und das Fenster seine Nachrichten behandeln kann.
    • RedrawWindow löst ebenfalls eine WM_PAINT Nachricht aus, kehrt aber erst dann zurück, wenn das Fenster tatsächlich neu gezeichnet worden ist.

    Kennst du dich mit dem Mechanismus der Windows Message Pump aus? Das solltest du verstanden haben, wenn du für Windows programmierst.



  • @DocShoe
    Wer kennt das Messaging schon komplett.
    Natürlich arbeite ich immer wieder mal mit SendMessage oder PostMessage.
    Bei einigen Automatismen bin ich natürlich nicht immer sicher.



  • @elmut19 sagte in Fenster wirklich neu zeichnen:

    Wer kennt das Messaging schon komplett.

    Die KI kann so etwas bestens.


Anmelden zum Antworten