Warum flackert mein Dialog, wenn ich ihn größer ziehe?



  • Hallo Forum,
    nachdem ich mein Problem mit den Buttons und Bitmaps gelöst habe, stehe ich vor dem nächsten Problem.
    Für meinen Dialog habe ich selbst eine Region definiert, in der der Benutzer anpacken und den Dialog größer/kleiner ziehen kann. Das funktioniert auch alles ganz wunderbar, nur flackert das ganze beim Ziehen gewaltig.
    Im Dialog sind nur Buttons (Klasse CPolyBtn von Codeproject), die halt neu gezeichnet werden 😕

    Danke schonmal! Ohne dieses Forum wäre ich schon oft völlig verloren gewesen!



  • Verdendest du beim zeichnen schonen eine MemoryDC Klasse, also zeichnet du erst in den Speicher? -> Double Buffering



  • Also die Methode DrawItem() aus der Klasse CPolyBtn sieht so aus

    void CPolyBtn::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 
    {
    	CRect rect = lpDrawItemStruct->rcItem;
    	CDC* pDC   = CDC::FromHandle(lpDrawItemStruct->hDC);
    	UINT state = lpDrawItemStruct->itemState;
    	UINT nStyle = GetStyle();
    
    	int nSavedDC = pDC->SaveDC();
    
        CBrush br;
        br.CreateSolidBrush(m_clrFill);
    
        // fill interior
        pDC->SetPolyFillMode(ALTERNATE);
        CBrush *ob = pDC->SelectObject(&br);
        pDC->Polygon(m_pPoints, m_edges.size());
        pDC->SelectObject(ob);
    
        pDC->SelectClipRgn(&m_rgn);
    
        // draw bitmap
       if (m_bmpID!=0)
       {
          CPoint pos = m_bmpOffset;
          if ((state & ODS_SELECTED))	
          {
             pos.x++;
             pos.y++;
          }
    
    	  if(m_bMouseOnButton)
    		_TransparentBlt(*pDC, m_bmp, pos.x, pos.y, m_clrTrans);
    	  else
    		_TransparentBlt(*pDC, m_bmpMouseover, pos.x, pos.y, m_clrTrans);
       }
    
       if ((state & ODS_DISABLED) && m_bmpIDD!=0)
       {
          _TransparentBlt(*pDC, m_bmpD, m_bmpOffset.x, m_bmpOffset.y, m_clrTransD);
       }
    
       // draw text
       CString txt;
       GetWindowText(txt);
       if (!txt.IsEmpty())
       {
          pDC->SetBkMode(TRANSPARENT);
          if ((state & ODS_DISABLED))
          {
             CSize cz = pDC->GetTextExtent(txt);
             pDC->DrawState(m_textOffset, cz, txt, DSS_DISABLED, TRUE, 0, (HBRUSH)NULL);
          }
          else
          {
             CPoint pos = m_textOffset;
             if ((state & ODS_SELECTED))	
             {
                pos.x++;
                pos.y++;
             }
             pDC->TextOut(pos.x, pos.y, txt);
          }
       }
    
       // paint the edges
       for (int i=0;i<m_edges.size();i++)
       {
          int iPenStyle = PS_SOLID;
    
          COLORREF clr = m_edges.at(i).clr;
    
    	  if(m_bMouseOnButton)
    		  clr = m_edges.at(i).rolloverclr;
    	  else 
    		  clr = m_edges.at(i).focusclr;
    		  /*
          if ((state & ODS_SELECTED))	
          {
             clr = m_edges.at(i).downclr;
          }
          else if ((state & ODS_DISABLED))
          {
             clr = m_edges.at(i).disabledclr;
          }
          else if (m_bMouseOnButton)
          {
             clr = m_edges.at(i).rolloverclr;
          }
    	  */
    
          CPen pen(iPenStyle, 1, clr);
    
          CPen *opp = pDC->SelectObject(&pen);
    
          pDC->MoveTo(m_edges.at(i).start);
          pDC->LineTo(m_edges.at(i).end);
    
          pDC->SelectObject(opp);
       }
    
       pDC->SelectClipRgn(NULL);
       pDC->RestoreDC(nSavedDC);
    }
    

    Ansonsten setze ich nur in OnSize() des Dialogs für jeden Button CRect neu. Die OnPaint()-Methode des Dialogs habe ich gar nicht verändert. Muss ich die Draw-Item Methode für die Buttons verändern und erst in einen MemoryDC zeichnen?



  • Versuch erst mal in OnEraseBkgnd FALSE zurückzugeben.



  • Also wenn ich in der OnEraseBkgnd() der Buttonklasse FALSE zurückgebe, ändert sich gar nichts.
    Gebe ich in meiner Dialogklasse bei OnEraseBkgnd() FALSE zurück, verschwindet der Hintergrund des Dialogs, d.h. es sind nur noch meine Buttons sichtbar, und außerdem verändert sich der Hintergrund des Dialogs nicht mehr, d.h. beim größer ziehen des Dialogs sieht man noch die Buttons vom kleineren Dialog usw.



  • Zufällig habe ich das gleiche Problem. OnEraseBkgnd sendet als Returnwert FALSE bei mir. Mit einer Display-Buffer-Klasse arbeite ich auch. Denoch flackert meine von CButton abgeleitete Zeichenfläche beim größer ziehen.

    Wäre es eine Lösung den Inhalt von DrawItem in OnEraseBkgnd zu schreiben.



  • Ok, ich meinte natürlich die Dialogklasse, sorry.
    Flackern tut es aber erst mal nicht mehr? Jetzt könntest du in der OnPaint des Dialogs den Hintergrund selbst zeichnen (FloodFill).
    Was mir aber gerade noch einfällt, rufst du in der OnSize Invalidate auf?
    Wenn ja, versuchs mal Invalidate(FALSE);



  • Ich habe Invalidate() nicht aufgerufen. Habs gerade mal probiert, aber das ändert auch nichts leider.
    Ich habe jetzt folgendes in meine OnPaint()-Methode geschrieben, aber es tut sich nichts. was mache ich falsch?

    void CStartdialog3Dlg::OnPaint() 
    {
    	if (IsIconic())
    	{
    		CPaintDC dc(this); // Gerätekontext für Zeichnen
    
    		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
    
    		// Symbol in Client-Rechteck zentrieren
    		int cxIcon = GetSystemMetrics(SM_CXICON);
    		int cyIcon = GetSystemMetrics(SM_CYICON);
    		CRect rect;
    		GetClientRect(&rect);
    		int x = (rect.Width() - cxIcon + 1) / 2;
    		int y = (rect.Height() - cyIcon + 1) / 2;
    
    		// Symbol zeichnen
    		dc.DrawIcon(x, y, m_hIcon);
    	}
    	else
    	{
    		CRect rect;
    		GetClientRect(&rect);
    
    		CPaintDC dc(this);
    
    		dc.FloodFill(rect.left, rect.top, RGB(148,147,170));
    
    		CDialog::OnPaint();
    	}
    }
    


  • Schau mal hier rein: http://www.codeproject.com/gdi/flickerfree.asp
    Vielleicht hilft Dir das weiter.



  • Hm, ok, also ich habe nochmal ein bisschen rumprobiert und bin dabei auf das Problem gestoßen, dass mein Dialog ja nicht rechteckig ist und ich deswegen mit

    dc.FloodFill(rect.left, rect.top, RGB(148,147,170));
    

    am falschen Punkt ansetze, da sich dieser Punkt gar nicht in meinem Dialog befindet. Ändere ich also auf

    CRect rect;
    GetClientRect(&rect);
    CDC* dc = this->GetDC();
    dc->FloodFill(d1.x, d2.x, RGB(148,147,170));
    CDialog::OnPaint();
    

    wird der Hintergrund immerhin weiß gezeichnet 😕



  • Hihi, sorry, das liegt daran, das wahscheinlich VS hinter dem Dialog liegt und dies als Hintergrund für den Dialog genommen wird. Guck mal genau da müstte auch Text stehen 😃
    Lass das Floodfill in OnPaint weg und
    versuch mal in OnEraseBkgnd folgendes:

    CRect rc;
    GetClientRect(&rc);
    CBrush brush(RGB(148,147,170));
    pDC->FillRect(&rc,&brush);
    return TRUE;
    


  • connan schrieb:

    Hihi, sorry, das liegt daran, das wahscheinlich VS hinter dem Dialog liegt und dies als Hintergrund für den Dialog genommen wird. Guck mal genau da müstte auch Text stehen

    Ähm, ja, da steht auch ab und an mal Text 🙄

    Die andere Möglichkeit hab ich mal ausprobiert. Jetzt ist der Hintergrund zwar wieder farbig, aber dafür flackern doch wieder alles beim ziehen. Ich hab auch nochmal zur Kontrolle FALSE zurückgegeben und da flackert das ganze Ding nicht so 😞



  • Ja, man muss, glaube ich, auch FALSE zurückgeben (hab nicht nachgeschaut 🙄 ).
    Aber jetzt dürften zumindest nur noch die Buttons flackern?



  • Tja, ich weiß nicht so genau was da flackert! Alles irgendwie 😞



  • Und wenn Du jetzt auch in OnEraseBkgnd der Buttons FALSE zurückgibst? Kann sein das Du dafür noch 'Benachrichtigen' einschalten musst.



  • Dann flackert immer noch alles 😞 😕

    Trotzdem vielen Dank fürs viele Antworten, irgendeine Lösung finde ich sicher noch!



  • Lass es uns aber wissen 😉
    Sorry, ich bin mit meinem Latein am Ende, vieleicht hilft ja wirklich nur noch ein MemDC 😕


  • Mod

    Das Flackern beim Dialog Resize lässt sich nicth mit Double Buffering lösen, denn jedes Fenster hat seinen eigenen DC!

    Besser WS_CLIPCHILDREN für den Dialog setzen!



  • Ich hab auch noch mal nachgeschaut und glaube, daß das hier genau das richtige für Dich ist:
    http://www.codeproject.com/buttonctrl/NoFlicker.asp?df=100&forumid=151835&exp=0&select=1036290
    Dort wird, wie schon von Martin vorgeschlagen, WS_CLIPCHILDREN benutzt.



  • Hallo!
    Ihr seid echt klasse 😃 Das flackern ist jetzt endlich weitgehend weg. Jetzt hab ich noch das Problem, dass ein Button nicht immer richtig gezeichnet wird. Aber das liegt vermutlich eher an meinem Code 😃
    Vielen vielen Dank nochmal!



  • Hm, also ich hab mir das nochmal genauer angeschaut und getestet.
    Wenn ich das Fenster schön ganz langsam größer ziehe, funktioniert alles super. Mache ich jetzt mit der Maus eine ganz schnelle Bewegung beim Fenster größer ziehen, bleibt einer der Buttons an der alten Stelle stehen. Ohne das Flag WS_CLIPCHILDREN passiert das nicht. Wie kann ich das jetzt noch abfangen?


Anmelden zum Antworten