Flicker Free mit Dialog in CStatic
-
Im folgenden Beispiel
http://www.pospiech.eu/download/flickerfreedemocstatic.zipmit einer Überladenen CStatic in einem Dialog die CMemDC zum Flackerfreien Zeichnen benutzt ist das Zeichnen nur dann ohne Flackern wenn auch im dahinterliegenden Dialog Fenster ein
BOOL CFlickerFreeDemoDlg::OnEraseBkgnd(CDC* pDC) { return FALSE; }gesetzt ist. Dann allerdings ist der Hintergrund des Dialogs weiß und bleibt somit nicht erhalten. Nehme ich die Funktion heraus, ist der Hintergrund ok, aber das ganze flackert wie vorher.
Auf allen Seiten zu Flicker Free konnte ich keinen Hinweis finden wie man das korrigiert.
Matthias
-
1. OnEraseBkGnd muss mit TRUE verlassen werden, wenn man vermeiden will, dass ein default Mechanismus greift. Ich weiß nicht warum in allen Samples FALSE returniert wird.
2. Das gilt für das Control nicht für das Parent.
3. Muss das Control in diesem Fall sich komplett (inkl. Background) selbst zeichnen.Wann flackert es denn bei Dir? Beim Neuaufbau des Dialoges?
Hier kann evtl. WS_CLIPCHILDREN helfen!Wann flackert es detailiert? Du musst nicht das ganze Parent invalidat'en um ein Neuzeichnen eines Controls zu verhindern.
-
Martin Richter schrieb:
1. OnEraseBkGnd muss mit TRUE verlassen werden, wenn man vermeiden will, dass ein default Mechanismus greift. Ich weiß nicht warum in allen Samples FALSE returniert wird.
2. Das gilt für das Control nicht für das Parent.
3. Muss das Control in diesem Fall sich komplett (inkl. Background) selbst zeichnen.Du willst mir damit sagen, dass alle Beispiele falsch sind, oder verstehe ich dich falsch?
Martin Richter schrieb:
Wann flackert es denn bei Dir? Beim Neuaufbau des Dialoges?
Hier kann evtl. WS_CLIPCHILDREN helfen!Wie kann ich das Überprüfen?
Martin Richter schrieb:
Wann flackert es detailiert? Du musst nicht das ganze Parent invalidat'en um ein Neuzeichnen eines Controls zu verhindern.
Das tue ich doch, oder nicht?
Den Quellcode sammt Projekt habe ich zum Download angegeben (siehe oben). Das sollte die meisten deiner Fragen schnelle beantworten.
Matthias
-
Ich habe die Specs noch mal gelesen. Es spielt mehr oder weniger keine große Rolle ob man FALSE oder TRUE returniert. Es wird dadurch nur ein Flag in der PAINTSTRUCT gesetzt.
Aber es gilt dennoch: Du musst OnEraseBkGnd im CStatic abfangen nicht im Parent!
Sag doch mal was bei Dir denn eigentlich flackert...
Ich gestehe Dir: Ich beantworte gerne Fragen, aber immer dazu ganze Projekte herunterladen zu müssen habe ich nicht so große Lust...
-
Martin Richter schrieb:
Aber es gilt dennoch: Du musst OnEraseBkGnd im CStatic abfangen nicht im Parent!
Ich habe die funktion im Parent und im CStatic. Ob es flackert hängt vom Parent ab. Wenn ich es auf false setzte flackert es nicht, dafür wird der Parent nicht mehr angezeigt - was ebenfalls falsch ist. Wenn ich es auf true setzte flackert es und der Hintergrund ist korrekt.
Martin Richter schrieb:
Sag doch mal was bei Dir denn eigentlich flackert...
Der Inhalt von CStatic
Martin Richter schrieb:
Ich gestehe Dir: Ich beantworte gerne Fragen, aber immer dazu ganze Projekte herunterladen zu müssen habe ich nicht so große Lust...
Glaube ich dir. Das Projekt ist allerdings wirklich nur eine Demo - quasi ein Minimalbeispiel.
Matthias
-
Martin Richter schrieb:
Hier kann evtl. WS_CLIPCHILDREN helfen!
Wenn ich WS_CLIPCHILDREN in den CFlickerFreeDemoDlg::OnInitDialog() einfüge
dann wird OnPaint in CStatic nicht mehr aufgerufen wenn ich in CStatic folgende Funktion aufrufevoid CGraphCtrl::UpdatePlot() { CRect rc; GetWindowRect(rc); GetParent()->ScreenToClient(rc); // Converts the screen coordinates of // a given point or rectangle on the display // to client coordinates. // Define Region to be redraw upon Update GetParent()->InvalidateRect(rc, TRUE); // Invalidates the client area within the // given rectangle by adding that rectangle // to the CWnd update region // TRUE: Erase Background GetParent()->UpdateWindow(); // sends a WM_PAINT message }Was mir bislang noch immer fehlt ist ein Beispiel in dem in ein untergeordnetes Fenster (wie bei mir in CStatic) gezeichnet wird. In allen mir bekannten Beispielen wird in das Fenster direkt gezeichnet.
Matthias
-
Meine weitere Analyse:
Wenn ich den Dialog aufBOOL CFlickerFreeDemoDlg::OnEraseBkgnd(CDC* pDC) { return FALSE; }setzte, dann flackert es nicht, aber der Dialog wird nicht mehr gezeichnet.
Bei
BOOL CFlickerFreeDemoDlg::OnEraseBkgnd(CDC* pDC) { return CDialog::OnEraseBkgnd(pDC); }wird der Dialog gezeichnet aber CStatic flackert.
In CStatic steht dabei folgendes:
BEGIN_MESSAGE_MAP(CGraphCtrl, CStatic) //{{AFX_MSG_MAP(CGraphCtrl) ON_WM_ERASEBKGND() ON_WM_PAINT() ON_WM_CREATE() //}}AFX_MSG_MAP ON_WM_SIZE() END_MESSAGE_MAP() BOOL CGraphCtrl::OnEraseBkgnd(CDC* pDC) { return FALSE; } void CGraphCtrl::OnPaint() { CPaintDC dc(this); // device context for painting CRect (rc); GetClientRect(rc); CMemDC pDC(&dc,&rc); COLORREF c; if ((m_PixelNumberX>0) && (m_PixelNumberY > 0)) { for (int ix=0; ix < m_PixelNumberX; ix++) { for (int iy=0; iy < m_PixelNumberY; iy++) { c=PlotData[ix][iy]; pDC->SetPixel(ix,iy,c); //dc.SetPixel(ix,iy,c); } } } }Ob ON_WM_ERASEBKGND() in CGraphCtrl dabei gesetzt ist oder nicht ist egal, und damit auch ob BOOL CGraphCtrl::OnEraseBkgnd(CDC* pDC) aufgerufen wird oder nicht.
Ehrlich gesagt verstehe ich die Zusammenhänge inzwischen überhaupt nicht mehr...
Wäre über eine Erklärung sehr erfreut.
Matthias
-
Also ich habe mir mal Deinen Code angesehen

Du hast nicht gelesen was ich Dir geschrieben habe!
1. Schmeiß OnEraseBkGnd aus dem CDialog Objekt raus.
2. Nur das Fenster das geändert (neu gezeichnet) werden soll benötigt ein Invalidate/UpdateWindow!Dein ganzer Fehler steckt in dieser Funktion
void CGraphCtrl::UpdatePlot() { CRect (rc); GetWindowRect(rc); // Points to a CRect object or a RECT structure // that will receive the screen coordinates of // the upper-left and lower-right corners. GetParent()->ScreenToClient(rc); // Converts the screen coordinates of // a given point or rectangle on the display // to client coordinates. // Define Region to be redraw upon Update GetParent()->InvalidateRect(rc, TRUE); // Invalidates the client area within the // given rectangle by adding that rectangle // to the CWnd update region // TRUE: Erase Background GetParent()->UpdateWindow(); // sends a WM_PAINT message }Warum in aller Welt führst Du ein Redraw auf dem Parent aus?
Warum ersetzt Du diese ganze Funktion nicht einfach durch
Invalidate(); UpdateWindow();Oder einfach
RedraeWindow();Weiterhin musst Du natürlich das laden der neuen Koordintaen auch in den Timer packen!
Rein aus OOP mässigen Gründen würde ich einfach in der Funktion SetPlotData ein Redraw erzwingen...