Invalidate funktioniert nicht immer



  • Hi,

    ich hab ein MFC Programm mit SDI Architektur.

    Darin eine Menüleiste.

    Beim Drücken einer der Buttons wird ein Dialog aufgerufen, da gibt man 3 Werte ein ( RGB Wert für meine Punkte), bei ONOK werden die Werte übernommen.
    Das übernehmen klappt.
    Danach ruf ich Invalidate() auf aber es wird nichts neu gezeichnet.

    Hab jetzt exra nen Actionhandler für LButtonDOwn gemacht damit mit linksklick manuell alles neugezeichnet wird.

    Ich möchte aber direkt nachdem die Viewklasse die neuen RGB werte des Dialoges übernommen hat einen bereich neu zeichnen lassen.
    Die Invalidate bzw. invalidaterect aufrufe werden anscheinend ienfach ignoriert.

    Hier mal die view klasse:
    (die sachen die ich meine stehen ganz am ende, das obere is nur falls einer denkt da oben läuft schon was falsch 🙂

    // Ex05aV2View.cpp : Implementierung der Klasse CEx05aV2View
    //
    
    #include "stdafx.h"
    #include "Ex05aV2.h"
    
    #include "Ex05aV2Doc.h"
    #include "Ex05aV2View.h"
    #include "RGBBox.h"
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    
    // CEx05aV2View
    
    IMPLEMENT_DYNCREATE(CEx05aV2View, CView)
    
    BEGIN_MESSAGE_MAP(CEx05aV2View, CView)
        ON_WM_PAINT()
        ON_WM_LBUTTONDOWN()
    END_MESSAGE_MAP()
    
    // CEx05aV2View-Erstellung/Zerstörung
    
    CEx05aV2View::CEx05aV2View()
    {
        // TODO: Hier Code zur Konstruktion einfügen
    
    }
    
    CEx05aV2View::~CEx05aV2View()
    {
    }
    
    BOOL CEx05aV2View::PreCreateWindow(CREATESTRUCT& cs)
    {
        // TODO: Ändern Sie hier die Fensterklasse oder die Darstellung, indem Sie
        //  CREATESTRUCT cs modifizieren.
    
        return CView::PreCreateWindow(cs);
    }
    
    // CEx05aV2View-Zeichnung
    
    void CEx05aV2View::OnDraw(CDC* pDC)
    {
        for(int i = 0; i <= 200; i++) {
            for(int j = 0; j <= 200; j++) {
                pDC->SetPixel(i, j, RGB(theApp.r, theApp.g, theApp.b));
            }
        }
        // TODO: Code zum Zeichnen der systemeigenen Daten hinzufügen
    }
    
    // CEx05aV2View-Diagnose
    
    #ifdef _DEBUG
    void CEx05aV2View::AssertValid() const
    {
        CView::AssertValid();
    }
    
    void CEx05aV2View::Dump(CDumpContext& dc) const
    {
        CView::Dump(dc);
    }
    
    CEx05aV2Doc* CEx05aV2View::GetDocument() const // Nicht-Debugversion ist inline
    {
        ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CEx05aV2Doc)));
        return (CEx05aV2Doc*)m_pDocument;
    }
    #endif //_DEBUG
    
    // CEx05aV2View-Meldungshandler
    void CEx05aV2View::OnRGBBox() {
        CRGBBox InsertRGB;
    
        if(InsertRGB.DoModal() == IDOK) {
            theApp.r = InsertRGB.m_nR;
            theApp.g = InsertRGB.m_nG;
            theApp.b = InsertRGB.m_nB;
        }
        Invalidate(NULL); // Funktioniert nicht
    }
    
    void CEx05aV2View::OnLButtonDown(UINT nFlags, CPoint point)
    {
        Invalidate(); // Funktioniert
    }
    

    Danke für eure Hilfe

    Daniela

    P.S. ich benutze Visual Studio 2005 Pro (gabs für Studenten an unserer FH kostenlos, MSDNAA Programm ) und Windows XP SP2



  • hallo Daniela,

    ich würde nach Invalidate(...) ein UpdateWindow() aufrufen.

    Invalidate(...);
    UpdateWindow();
    

    ohne das UpdateWindow zwingst du dein fenster auch nicht zum neu zeichen.
    wenn du dein fenster aber verschieben würdest oder es durch ein anderes
    fenster überdecken würdest und es dann wieder zum vorschein holst, dann
    müsstest du ohne das UpdateWindow deine neue farbe sehen.



  • Hi, danke für den Tipp.

    Aber ich habe gedacht ein Invalidate erzeugt die Message WM_PAINT und dann muss es neugezeichnet werden..
    Bei den anderen Invalidate-Aufrufen klappts ja auch ohne

    Nun denn, habs mal mit UpdateWindow() probiert, aber es passiert nichts.

    Hab nun auch gesehen, dass beim verschieben des fensters ebenfalls nichts passiert.

    Nur wenn ich links klicke (siehe Actionhandler) oder ich die grösse änder oder in anderes fenster über dem zeichenbereich war, nur dann wird neugezeichnet.

    Ich selbst kann da anscheindn keine Neuzeichnung erzwingen, gehen muss es aber, andere Programme machen es ja auch so

    trotzdem danke für den Tipp 🙂

    cya Daniela



  • daniela schrieb:

    Aber ich habe gedacht ein Invalidate erzeugt die Message WM_PAINT und dann muss es neugezeichnet werden..
    Bei den anderen Invalidate-Aufrufen klappts ja auch ohne

    Nein, Invalidate() merkt sich nur den Bereich, der neugezeichnet werden muß - das passiert bei der nächsten Gelegenheit, wenn dein Programm unbeschäftigt ist (oder WM_PAINT von woanders kommt).



  • CStoll schrieb:

    Nein, Invalidate() merkt sich nur den Bereich, der neugezeichnet werden muß - das passiert bei der nächsten Gelegenheit, wenn dein Programm unbeschäftigt ist (oder WM_PAINT von woanders kommt).

    seltsam, ich dachte immer UpdateWindow() sagt dem fenster
    das es genau die WM_PAINT message senden/bekommen soll ?!?

    MSDN schrieb:

    The UpdateWindow member function sends a WM_PAINT message directly, bypassing the application queue. If the update region is empty, WM_PAINT is not sent.

    wenn ich einen bereich in einem fenster, meistens in einem dialog,
    neu zeichnen möchte, dann invalidiere ich nur diesen einen bereich
    und sende dann update:

    CRect rechteck( left, top, right, bottom);
    InvalidateRect( rechteck);
    UpdateWindow();
    

    ich glaube sogar das es möglich ist mit einem RedrawWindow() das gesamte
    fenster neu zeichen zu lassen, allerdings kommt es hier zu sehr unschönem
    flackern in dem fenster...

    ABER: ich sehe gerade das daniela in der OnDraw methode neu zeichnet,
    müsste das zeichen nicht in der OnPaint methode geschehen???

    habe gerade noch mal in der msdn gelesen:

    MSDN schrieb:

    The framework calls this member function when Windows or an application makes a request to repaint a portion of an application's window.
    afx_msg void OnPaint( );
    The WM_PAINT message is sent when the UpdateWindow or RedrawWindow member function is called.



  • Hi, danke für den Hinweis.

    Welche Methode genau wird denn bei der Message WM_PAINT aufgerufen ?

    Ich dachte immer OnDraw ?

    Kannst du mir mal den Link geben ?

    Ich hab in der MSDN ein wenig herumgesucht aber ich finde die MFC-Seiten nicht, hab nur die .Net Doku usw gefunden.

    Soweit schon mal danke.

    Ein RedrawWindow führt auch nicht zum neuzeichnen.

    Nur eine Grössenänderung oder ein durch einen Klick selbst erzwungene Message führt zum aktualisieren.

    cya



  • Ok, MFC Doku hab ich jetzt gefunden.

    Hab auf der deutschen MS Seite herumgesurft und da findet er nichts zu MFC. Hab auf die englische MSDN Seite gehen müssen.

    cya



  • Jaipur schrieb:

    CStoll schrieb:

    Nein, Invalidate() merkt sich nur den Bereich, der neugezeichnet werden muß - das passiert bei der nächsten Gelegenheit, wenn dein Programm unbeschäftigt ist (oder WM_PAINT von woanders kommt).

    seltsam, ich dachte immer UpdateWindow() sagt dem fenster
    das es genau die WM_PAINT message senden/bekommen soll ?!?

    Genau das meinte ich mit "oder WM_PAINT von woanders kommt" 😉 (ich war mir nicht ganz sicher, wer sich alles darum kümmert, WM_PAINT zu schicken)



  • OnDraw für SDI ist aber richtig. Das ist ja auch eine abstrakte Methode in der Basisklasse und muss daher überschrieben werden.



  • Ja.

    Also rein theoretisch müsste es funktionieren, wieso klappt es bei einem Mausklick aber nicht bei einem modalem Dialog ?

    Wie lösen denn andere Programmierer dieses Problem ?


Anmelden zum Antworten