Bug: VC-2010 MFC CFormView zeichnet Buttons beim Rollen falsch, es erscheinen schwarze Blöcke

In der MFC 10.0 hat sich ein Bug eingeschlichen, der sich unter Windows Vista und Windows 7  bemerkbar macht. Unter Windows XP tritt der Fehler nicht auf. Das Problem tritt in jedem Stil auf, der DWM verwendet. D.h. nicht wenn Windows klassisch ausgewählt wird.

Wenn auf einen CFormView mehrere Buttons liegen und der CFormView gerollt wird, dann kommt es unter Umständen zu Fehlern beim Neuzeichnen von Buttons. Dies schließt alle Button-Formen ein: Check-Buttons, Radio-Buttons und normale Buttons.

Das Ganze sieht nach dem Rollen in etwa so aus:

Der Text einiger Buttons erscheint nach dem Rollen als schwarze Blöcke. Es kann auch vorkommen, dass nur Teile der Buttons falsch gezeichnet werden.

Um das Problem gezielt nachzuvollziehen habe ich ein kleines Sample gebaut. Man kann durch zwei Schalter den CScrollView gezielt nach oben oder unten Rollen. Beim Rollen nach unten und bei bestimmten Fenstergrößen tritt dann der Fehler auf. Ich habe das Main-Window entsprechend beim Start in der Größe angepasst.

Das Problem liegt in einer Implementierung von WM_PRINTCLIENT in CScrollView (CScrollView::OnPrintClient), die ein Double-Buffering verwendet, dass entweder falsch ist oder sich eben mit der Standardimplementierung eines Dialoges beißt. Auf den ersten und zweiten Blick konnte ich in der Implementierung selbst keinen Fehler sehen. Deshalb vermute ich, dass sich dieses Double-Buffering mit dem auch vorhandenen Double-Buffering in den Standardimplementierungen der Dialogklasse beißt bzw. nicht korrekt berücksichtigt, dass auch Child-Windows neu gezeichnet werden müssen.

Die Lösung ist entsprechend einfach:

  • Man fügt einfach einen Handler für WM_PRINTCLIENT in seiner von CFormView abgeleiteten Klasse ein.
  • Dieser Handler ruft dann nicht die Implementierung der Basisklasse CFormView auf, sondern die Implementierung in CView (CView::OnPrintClient).
...
ON_MESSAGE(WM_PRINTCLIENT,&CScrollDialogMFCView::OnPrintClient)
...

LRESULT CScrollDialogMFCView::OnPrintClient( WPARAM wp, LPARAM lp )
{
  // Bypass the CScrollView::OnPrintClient implementation
  return CView::OnPrintClient(wp,lp);
}

Dieser Fehler ist in keiner der vorhergehenden MFC Versionen vorhanden (auch nicht in MFCNext), weil einfach kein entsprechender Handler vorhanden war..

Es stellt sich wohl bei einigen jetzt die Frage warum dieser Handler eingebaut wurde. Auch die Antwort ist einfach:
Seit Windows Vista wird stark von AnimateWindow Gebrauch gemacht und auch DWM intern scheint des öfteren WM_PRINT/WM_PRINTCLIENT zu verwenden. Entsprechend haben fast alle Klassen in der MFC entsprechende Handler ergänzt bekommen.

Das Sample kann man hier herunterladen: ScrollDialogMFC – VS-2010.
Ich habe in der stdafx.h einen define FIX_CSCROLLVIEW_PROBLEM eingebaut mit dem man den Fix einfach aktivieren und deaktivieren kann.

2 Gedanken zu „Bug: VC-2010 MFC CFormView zeichnet Buttons beim Rollen falsch, es erscheinen schwarze Blöcke“

  1. Ich verwende ein CButton Objekt als Checkbox innerhalb einer Scrollview, die mittels SubclassDlgItem auf einer FormView eingebunden ist.
    Bisher VC2005 bin ich mit dieser Lösung gut zurecht gekommen.
    Mit VC2010 und Windows 7 habe ich das oben beschriebene Problem.

    Habe in allen Ebenen
    ON_MESSAGE(WM_PRINTCLIENT,&CDeliveryPackageView::OnPrintClient)
    eingefügt, aber ohne Erfolg.
    Ich denke es liegt an SubclassDlgItem.

    Den Beispielcode kann ich gerne schicken, benötige aber eine EMail-Adresse.

    CFormView::OnInitialUpdate()
    {

    m_pDeliveryPackage = new CDeliveryPackageView();
    if(m_pDeliveryPackage)
    {
    m_pDeliveryPackage->SubclassDlgItem(IDC_EDIT, this);
    }
    }

    CDeliveryPackageView::OnInitialUpdate() //* von CScrollView abgeleitet
    {

    m_pButton=(CButton*) new CButton();
    m_pButton->Create(_T(„Test“), WS_CHILD|BS_AUTOCHECKBOX|WS_TABSTOP|WS_VISIBLE,
    CRect(0, 0, 50, 15), this, 12345);

    m_pButton->ModifyStyle(BS_USERBUTTON,0,SWP_FRAMECHANGED);
    m_pButton->ModifyStyleEx(0,WS_EX_NOPARENTNOTIFY,SWP_FRAMECHANGED);


    }

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

I accept that my given data and my IP address is sent to a server in the USA only for the purpose of spam prevention through the Akismet program.More information on Akismet and GDPR.

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.