Rafraichissement graphique

Résolu
Signaler
-
 Utilisateur anonyme -
Bonjour!

Je réalise une application (MFC) qui comporte une boite de dialogue où je trace un graphique.

Cette boite de dialogue comporte quelques controles (boutons, Cedit...) à gauche, et à droite le graphique (qui est dessiné dans la fonction OnPaint). J'ai un thread qui envoie à intervalles réguliers un message à ma boite de dialogue, lorsque ce message est intercepté, je met à jour le graphique grâce à InvalidateRect(CRect,TRUE), CRect ne comportant que la partie droite de ma boite de dialogue (uniquement la partie graphique).

Lorsque je compile en mode débug, tout se passe bien, mais lorsque je compile en mode Release, un erreur
de mémoire se produit ("la mémoire ne peut pas être read").

Cette erreur se produit uniquement lorsque le pointeur de la souris passe sur un controle, ou lorsque je déplace ma fenetre. De plus, si je rafraichi ma fenetre avec la méthode Invalidate(), l'erreur se produit immédiatement, de même si le CRect de ma méthode InvalidateRect(CRect,TRUE) comporte la partie contenant les controles.

Je suppose donc que c'est le rafraichissement des controles qui pose problème, mais je ne comprend pas où est l'erreur, et encore moins comment la corriger...

Quelqu'un peut-il m'aider?

8 réponses

Messages postés
653
Date d'inscription
mardi 6 décembre 2005
Statut
Membre
Dernière intervention
10 novembre 2014
2
T'as essayer de rafraichir toute la fenetre avec:
InvalidateRect(hwnd, 0, TRUE);
hwnd etant le handle de ta form.

Neo_Fr
Messages postés
1905
Date d'inscription
mercredi 22 janvier 2003
Statut
Membre
Dernière intervention
17 septembre 2012
3
Salut,

Si tu dessines toi même le fond de ton graphique dans le OnPaint(), tu peux juste faire InvalidateRect(0,FALSE).

Si les boutons sont directement positionnés sur la fenetre ou tu
dessines, tu peux ptet essayer de mettre le style WS_CLIPCHILDREN a la
fenetre ou tu dessines.

Et enfin pour les erreurs, sans code on ne peux pas faire grand chose.

Finalement en combinant vos 2 réponses ça marche très bien donc encore merci... J'avais du faire une mauvaise manip dans mon OnPaint() à force de tout bidouiller...

Je met le code pour ceux que ça intéresse, il permet donc de repeindre une fenetre depuis un thread, en evitant l'effet de scintillement.

void COscilloscope::OnPaint()
{
    CPaintDC fdc(this); // device context for painting

    CDC *pDC;
 
    pDC=GetDC();

    CRect lRect;
    GetClientRect(lRect);
    lRect.NormalizeRect();

     //mise en place du double-buffering
    CDC dc;
    dc.CreateCompatibleDC(pDC);

    //on y ajoute un bitmap pour agrandir dc
    CBitmap memBmp;
    memBmp.CreateCompatibleBitmap(pDC, lRect.Width(), lRect.Height());
    CBitmap* OldBmp = dc.SelectObject(&memBmp);

    //On va peindre le fond
    CBrush backBrush(RGB(250,250,250));
    dc.FillRect(lRect,&backBrush);

    //Ces trois fonctions permettent de dessiner sur la boite de dialogue
     DrawLine(&dc);
    DrawRepere(&dc);
    DrawGraph(&dc);

     //on bascule dc vers fdc
    fdc.BitBlt(0,0,lRect.Width(),lRect.Height(),&dc,0,0,SRCCOPY);
    dc.SelectObject(OldBmp);
    dc.DeleteDC();
    memBmp.DeleteObject();
 
    ReleaseDC(pDC);
}

UINT ThreadFonction(LPVOID Param){
    
    while(m_TransfertContinu){     //On effectue le thread tant que la variable m_tranfertContinu=TRUE
        
        InvalidateRect((HWND)Param,0,FALSE); //le HWND de ma fenetre est passé à mon thread en paramètre
        Sleep(40);
    }
    return 0;
}

Ne pas oublier de mettre votre boite de dialogue en style WS_CLIPCHILDREN!

En faisant InvalidRect(hwnd,0,TRUE) depuis mon thread l'erreur est en partie corrrigée.

Le problème est que j'ai mis en place un double buffering pour éviter le scintillement de mon grahique, mais lorsque je rafraichit toute la fenêtre, les boutons scintillent (contrairement au graphique). C'est pour cela que je rafraichissait seulement une partie de ma boite de dialogue.

En plus, l'erreur se produit toujours lorsque je déplace ou que je redimensionne ma fenetre, mais seulement quand le double buffering est mis en place, et pas quand je dessine directement sur la boite de dialogue.

Donc je vais essayer de voir tout ça! Merci beaucoup pour ta réponse!

Le style WS_CLIPCHILDREN permet bien d'éviter le scintillement des boutons, merci!

Voici une partie de mon code. C'est avec ce code que se produit l'erreur décrite dans le premier post...

J'ai essayé de remplacer l'envoi du Message WM_UPDATE_UI dans mon thread par InvalidateRect(hwnd,0,TRUE) mais mon graphique scintille fortement (on dirai que le double buffering n'est plus effectué)...

//Fonction exécutée par mon thread :

UINT ThreadFonction(LPVOID Param){
   
    while(GLOB->m_TransfertContinu){ //On effectue la boucle tant qu'une variable globale est à TRUE

        PostMessage((HWND)Param,WM_UPDATE_UI,0,0);
        Sleep(100);
    }
    return 0;
}

//Fonction exécutée lors de l'interception du message WM_UPDATE_UI

void COscilloscope::OnUpdateUI()
{
    this->InvalidateRect(0,FALSE);
}

//Fonction OnPaint :

void COscilloscope::OnPaint()
{
    CPaintDC fdc(this); // device context for painting

    CRect lRect;
    GetClientRect(lRect);
    lRect.NormalizeRect();

    pDC = GetDC();
    dc.CreateCompatibleDC(pDC);

    //on y ajoute un bitmap pour agrandir dc
    memBmp.CreateCompatibleBitmap(pDC, lRect.Width(), lRect.Height());
    CBitmap* OldBmp = dc.SelectObject(&memBmp);

    //Remplissage du fond
    CBrush backBrush(RGB(250,250,250));
    dc.FillRect(lRect,&backBrush);

    //Ces trois fonctions permettent de dessiner mon graphique (le prog plante même si elles ne sont pas exécutées donc l'erreur ne vient pas de la)
     DrawLine(&dc, 6);
    DrawRepere(&dc);
    DrawGraph(&dc);

    //fdc.BitBlt(0,0,lRect.Width(),lRect.Height(),&dc,0,0,SRCCOPY);    //on copie dc vers fdc (solution 1)
    pDC->BitBlt(0,0,lRect.Width(),lRect.Height(),&dc,0,0,SRCCOPY);    //on copie dc vers fdc    (solution 2)
    //Ces 2 solutions de copie ne changent pas mon problème!
    dc.SelectObject(OldBmp);
    dc.DeleteDC();
    memBmp.DeleteObject();
 
    ReleaseDC(pDC);
}

Désolé je me suis trompé dans mon précédent post...

J'ai essayé de remplacer l'envoi du Message WM_UPDATE_UI dans mon
thread par InvalidateRect(hwnd,0,FALSE) . Je n'ai dans ce cas plus de problème de scintillement, par contre, mon erreur se produit lorsque que je déplace, redimensionne ou ferme la fenetre...
Messages postés
1905
Date d'inscription
mercredi 22 janvier 2003
Statut
Membre
Dernière intervention
17 septembre 2012
3
Salut,

Une petite remarque a propos du dernier code: le GetDC/ReleaseDC est inutile, c'est le fdc qu'il faut utiliser.

Oui effectivement mon pDC ne sert à rien, merci.
On peut donc supprimer les lignes "CDC *pDC;", "pDC=GetDC();" et "ReleaseDC(pDC);" et remplacer les "pDC" par des "&fdc".