kein WM_PAINT in Kindeskindern



  • Hallo,

    ich habe ein Problem, was ich leider noch nicht runterbrechen konnte. Irgendwo ist ein Hau in meiner selbstgeschriebenden und historisch gewachsenen Klassenbibliothek.

    Ich erzeuge innerhalb der WM_CREATE Behandlung von Win1 (Win1 ist Dialog) neue Kinder (Win2). In deren WM_CREATE neue Enkelkinder (etc. Win3, Win4).

    Problem die Enkel werden nicht gezeichnet. Nur wenn ich das Fenster bewege (WM_SIZE). Auch nach Invalidate() wird nichts gezeichnet. Nur nach Update().

    Es ist auch egal ob ich die in WM_CREATE Behandlung, also innerhalb von CreateWindowEx() oder danach erzeuge.

    Irgendwie kommt kein WM_PAINT, auch kein Initiales bei den Enkeln, aber bei den Kindern an. Was komisch ist, denn Win2 verhält sich zu Win1, genauso wie Win3 zu Win2.

    Hat jemand eine Idee ohne den Code zu kennen, was da falsch sein könnte?
    Insbesondere wundert mich, dass WM_SIZE und WM_CREATE durchkommt.
    Auch WM_MOUSE_MOVE. Nur WM_PAINT wird allen Anschein nach nicht an die Enkel gereicht.

    Ich versuch es parallel runter zu brechen. Aber ein Tipp, wenn jemand eine Idee hat, dass es so oder so aussieht, wäre hilfreich.

    Danke und Gruß Thomas



  • Haben die Enkel eine Höhe oder Breite von 0? Offscreen positioniert? WS_VISIBLE vergessen?
    Hast du eine Endlosschleife von Invalidates und Updates? (Windows nimmt nur so 4000-10000 Nachrichten in die Message Queue auf).
    Hast du mit ClipChildren oder so gespielt?
    Segfault in der WM_PAINT? (Die werden gefressen bei 32-Bit-Anwendungen auf 64 Bit)



  • nwp3 schrieb:

    Hast du eine Endlosschleife von Invalidates und Updates? (Windows nimmt nur so 4000-10000 Nachrichten in die Message Queue auf)

    Interessanter Gedanke. Danke. Ich hab da mal ein Auge drauf.



  • Jetzt verstehe ich gar nichts mehr.

    In meiner Window-Klasse (gemeint ist c++-Klasse) gibt es eine Methode PaintAll();
    Diese wird bei WM-PAINT in der Handlermethode des Fensters aufgerufen:
    Die Handlermethode selbst wird über eine map mit Key Window-Handel (hwnd) zum eigentlichen Fenster (c++-Objekt) aufgerufen.

    Das ist der private Messagehandler von TTWin:
    (auf WM_PAINT gekürzt)

    LRESULT ttwin::TTWin::Messagehandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
      switch(msg){
        case WM_PAINT:
          PaintAll();
          return FALSE;
    

    Das ist der eigentliche globale von Windows, dessen Adresse an den Windows-Klassen registriert wird, als statische Member-Funktion.

    LRESULT CALLBACK ttwin::TTWin::MainCallback(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
    
      //forward to the actual window object
      TTWin* win = TTWinCallBackMap[hwnd];
      if (!win){
        if (msg == WM_CREATE || msg == WM_INITDIALOG){
          const CREATESTRUCT* const cs = reinterpret_cast<LPCREATESTRUCT>(lParam);
          win = reinterpret_cast<TTWin*>(cs->lpCreateParams);
          if (win){
            TTWinCallBackMap[hwnd] = win;
            //set Hwnd and Hinst. It is needed in child windwos before CreateWinEx returns! 
            win->Hwnd = hwnd;
          }
        } 
      } 
      if (win){
        return win->Messagehandler(hwnd, msg, wParam, lParam);
      }
      else{
        return ::DefWindowProc(hwnd, msg, wParam, lParam);
      }
    }
    

    Diese PaintAll()-Methode ist virtuell und war in den den Kind-Klassen - nicht aber in den Urenkeln! - leer implementiert. Als ich explizit die Basisklassen Funktion aufgerufen habe, geht alles wieder ... hä?

    Basisklassen-PaintAll:

    void ttwin::TTWin::PaintAll(){
    
      PAINTSTRUCT ps;
      HDC hdc = ::BeginPaint(Hwnd, &ps);
    
      RECT rect;
      ::GetClientRect(Hwnd, &rect);
      if (BackgroundImage) BackgroundImage->Init(hdc);
      DrawBackground(hdc, true);   
    
      //used pens etc.
      HPEN outline = ::CreatePen(PS_SOLID, 1, RGB(255, 255, 0)); 
    
      rect.bottom -= 1;
      rect.right -=1;
    
      POINT point;
      HGDIOBJ orgpen = ::SelectObject(hdc, outline);
      MoveToEx(hdc, rect.left,  rect.top, &point);
      LineTo  (hdc, rect.right, rect.top); 
      LineTo  (hdc, rect.right, rect.bottom); 
      LineTo  (hdc, rect.left,  rect.bottom); 
      LineTo  (hdc, rect.left,  rect.top); 
    
      //select the original pens
      ::SelectObject(hdc, orgpen);
    
      //delete all objects after use
      ::DeleteObject(outline);  
    
      //free device context
      ::EndPaint(Hwnd, (LPPAINTSTRUCT)&ps);
    }
    

    Backimage ist null und DrawBackground() macht nichts weltbewegendes.

    Genau genommen genügt der Aufruf von

    HDC hdc = ::BeginPaint(Hwnd, &ps);
    

    Alles andere kann in PaintAll() der Kinder und Enkel auskommentiert werden. Sind ja eh nur Container. (d.h. später muss man der Hintergrund gemalt werden)
    Erst die eigentlichen Urenkel malen was richtiges.

    Aber in der gesamten Hierachie muss jeder BeginPaint aufrufen.

    Das verstehe ich nicht.


Anmelden zum Antworten