IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

MFC Discussion :

L'association InflateRect+InvalidateRect pour déplacer un rectangle ? DPtoLP ?


Sujet :

MFC

  1. #1
    Membre expérimenté
    Avatar de randriano
    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Madagascar

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 219
    Points : 1 438
    Points
    1 438
    Par défaut L'association InflateRect+InvalidateRect pour déplacer un rectangle ? DPtoLP ?
    Bonsoir !

    Avant, j'ai utilisé pDC->Rectangle() et pDC->TextOut() pour écrire dedans; ensuite, j'utilisais alors la méthode SetROP2() pour déplacer le rectangle avec le texte dessus, pour le texte il fallait encore plus d'ingéniosité !!
    Récemment, j'ai découvert une autre technique, meilleure mais qui fait que les figures tracés ne tremblent pas ni ne saccadent à chaque invalidation (rafraîchissement) où les figures sont stockés dans une liste (CObArray par ex) mais il déplacer très bien une zone rectangulaire avec divers motifs dedans . Cette technique c'est l'utilisation de InflateRect() suivi après de InvalidateRect().
    Comment les utiliser ?? J'ai vu dans le sample MFC de MSDN une utilisation :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    void CDrawView::InvalObj(CDrawObj* pObj)
    {
    	CRect rect = pObj->m_position;
    	DocToClient(rect);
    	if (m_bActive && IsSelected(pObj))
    	{
    		rect.left -= 4;
    		rect.top -= 5;
    		rect.right += 5;
    		rect.bottom += 4;
    	}
    	rect.InflateRect(1, 1); // handles CDrawOleObj objects
    	InvalidateRect(rect, FALSE);
    }
    Ne tiens pas compte de CDrawObj mais on n'utilisera que m_position la zone rectangulaire de cet objet !!

    Entre temps, c'est quoi ?? sa syntaxe : void DPtoLP( LPRECT lpRect ) const;

    Merci bcp d'avance !!

  2. #2
    Membre confirmé Avatar de stephdim
    Profil pro
    Inscrit en
    Août 2007
    Messages
    462
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 462
    Points : 521
    Points
    521
    Par défaut
    Salut,

    tu parles de l'exemple DrawCli je suppose ?

    la technique dont tu parles n'a rien a voir avec InvalidateRect et InflateRect.

    la technique utilisée par DrawCli est l'OffScreen.

    le principe est simple :

    au lieu de dessiner directement sur l'ecran, on dessine dans un bitmap et apres on transfere le bitmap a l'ecran. l'effet de sacade (ou scintillement) disparait parce que la mise à jour est quasi instantanée (juste a transferer du bitmap vers l'ecran)

    DrawCLI est completement basé sur cette technique

    l'inconvenient est la consommation mémoire du bitmap - s'il y a une grosse portion de la fenetre a redessiner, le bitmap atteint vite qque megas en 24 bits / pixel ... mais de nos jour vu le prix des barrettes ...

    pour le code ça donne qque chose comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     
    void CMaVue:OnDraw(CDC *pDC)
    {
      CRect clipbox;
      if (pDC->GetClipBox(clipbox)<=NULLREGION)      // rectangle a dessiner
        return;                  // rien a dessiner ...
     
      CDC memdc;
      if (memdc.CreateCompatibleDC(pDC))      // création d'un Device Context mémoire
      {
        // création du bitmap
        CBitmap bitmap;
        if (bitmap.CreateCompatibleBitmap(pDC,clipbox.Width(),clipbox.Height()))
        {
          // sélection du bitmap
          CBitmap *pOldBitmap=memdc.SelectObject(&bitmap);
     
          memdc.SetViewportOrg(-clipbox.TopLeft());    // réglage origine
     
          // y a plus qu'a dessiner ici dans memdc au lieu de pDC
     
     
          // ici on transfert du bitmap vers l'ecran
          pDC->BitBlt(clipbox.left,clipbox.top,clipbox.Width(),clipbox.Height(),&memdc,0,0,SRCCOPY);
     
          memdc.SelectObject(pOldBitmap);
        }
      }
    }

    c'est tout simple ; j'ai fais ça de tete j'ai surement du faire des boulettes sur la syntaxe .... mais grosso modo c'est comme ça qu'on fait

    @+

  3. #3
    Membre expérimenté
    Avatar de randriano
    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Madagascar

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 219
    Points : 1 438
    Points
    1 438
    Par défaut
    Bonjour !

    Alors j'avais tout faux sur InflateRect+InvalidateRect !!
    En effet, je faisais référence au sample DrawCli dans ce thread.
    Citation Envoyé par stephdim
    la technique utilisée par DrawCli est l'OffScreen.
    Le vrai truc est donc CMemDC et le transfert de toute l'image dans un bitmap d'abord. Or, je ne vois aucune MemDC dans ce sample.
    Si je comprends bien donc c'est l'OnDraw de DrawCli qui fait cela !! Génial cette technique !! Le voici pour le traiter:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    void CDrawView::OnDraw(CDC* pDC)
    {
    	CDrawDoc* pDoc = GetDocument();
    	ASSERT_VALID(pDoc);
     
    	CDC dc;
    	CDC* pDrawDC = pDC;
    	CBitmap bitmap;
    	CBitmap* pOldBitmap = 0;
     
    	// only paint the rect that needs repainting
    	CRect client;
    	pDC->GetClipBox(client);
    	CRect rect = client;
    	DocToClient(rect);
     
    	/*if (!pDC->IsPrinting())
    	{
    	//Je l'ai enlevé car je le trouve inutile
    	}*/
     
    	// paint background
    	CBrush brush;
    	if (!brush.CreateSolidBrush(pDoc->GetPaperColor()))
    		return;
     
    	brush.UnrealizeObject();
    	pDrawDC->FillRect(client, &brush);
     
    	pDoc->Draw(pDrawDC, this);
     
    	if (pDrawDC != pDC)
    	{
    		pDC->SetViewportOrg(0, 0);
    		pDC->SetWindowOrg(0,0);
    		pDC->SetMapMode(MM_TEXT);
    		dc.SetViewportOrg(0, 0);
    		dc.SetWindowOrg(0,0);
    		dc.SetMapMode(MM_TEXT);
    		pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(),
    			&dc, 0, 0, SRCCOPY);
    		dc.SelectObject(pOldBitmap);
    	}
     
    }
    //Dans le doc
     
    COLORREF GetPaperColor() const { return m_paperColor; }
     
    CDrawDoc::CDrawDoc()
    {
    	EnableCompoundFile();
     
    	m_nMapMode = MM_ANISOTROPIC;
    	m_paperColor = RGB(255, 255, 255);
    //....................
    }
    "CBrush brush" ne sert que pour tracer le background en blanc puis "pDrawDC->FillRect(client, &brush)" l'exécute car sinon le view affichera une partie de l'écran. Je ne vois pas aussi l'utilité de "CDC dc".
    Je me trompe ou n'est-ce pas cette ligne qui effectue l'offscreen:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(),&dc, 0, 0, SRCCOPY);

  4. #4
    Membre confirmé Avatar de stephdim
    Profil pro
    Inscrit en
    Août 2007
    Messages
    462
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 462
    Points : 521
    Points
    521
    Par défaut
    Tu es obligé de passer par un "Memory Device Context" pour dessiner sur un bitmap.

    Dans la partie que tu as enlevé car tu l'as trouvait inutile, c'est justement là ou le memory device context etait créé et affecté a la variable pDrawDC.

    Quand on affiche a l'ecran on utilise l'OffScreen. Quand on imprime, on dessine directement dans le DC passé en parametre a OnDraw()

    @+

  5. #5
    Membre expérimenté
    Avatar de randriano
    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Madagascar

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 219
    Points : 1 438
    Points
    1 438
    Par défaut
    Bonjour !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if (!pDC->IsPrinting())
    {
    //Je l'ai enlevé car je le trouve inutile
    }
    Ne sert-il pas seulement que pour l'impression de la view or je n'en ai pas besoin pour l'instant? car le prog marche toujours très bien même si je l'enleve

    Qu'est-ce qui remplace donc le SetROP2() dans le traçage et la sélection ?? Que fait InvalObj() dans tout ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    void CDrawView::InvalObj(CDrawObj* pObj)
    {
    	CRect rect = pObj->m_position;
    	DocToClient(rect);
    	if (m_bActive && IsSelected(pObj))
    	{
    		rect.left -= 4;
    		rect.top -= 5;
    		rect.right += 5;
    		rect.bottom += 4;
    	}
    	rect.InflateRect(1, 1); // handles CDrawOleObj objects
     
    	InvalidateRect(rect, FALSE);
    }

  6. #6
    Membre confirmé Avatar de stephdim
    Profil pro
    Inscrit en
    Août 2007
    Messages
    462
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 462
    Points : 521
    Points
    521
    Par défaut
    Ne sert-il pas seulement que pour l'impression de la view or je n'en ai pas besoin pour l'instant? car le prog marche toujours très bien même si je l'enleve
    Non au contraire, il sert quand on est pas dans le cas de l'impression, donc pour l'offscreen. Alors autant dessiner normalement sans passer par l'offscreen, et dans ce cas là tu enleves tout le code pour ne travailler qu'avec le paramètre pDC.

    Qu'est-ce qui remplace donc le SetROP2() dans le traçage et la sélection ?? Que fait InvalObj() dans tout ça :
    Ne melanges pas SetROP2 qui est une autre technique et l'OffScreen. DrawCli utilise uniquement l'Offscreen (bcp plus lourd en ressource que l'autre technique)

    InvalObj() sert uniquement a invalider une zone de la fenetre pour qu'elle soit redessinée au prochain WM_PAINT qui lancera OnDraw(). Rien a voir avec une quelconque technique d'optimisation --> simplement pour rafraichir le dessin

    @+

  7. #7
    Membre expérimenté
    Avatar de randriano
    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Madagascar

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 219
    Points : 1 438
    Points
    1 438
    Par défaut
    Bonjour tout le monde !

    Je retourne sur ce thread pour confirmer donc que c'est la méthode OnDraw seulement de DrawCli qui permet de faire l'affichage sans saccade !! Il suffit donc de le copier et de remplacer à chaque programme le draw général
    void CDrawView::OnDraw(CDC* pDC)
    {
    CDrawDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);

    CDC dc;
    CDC* pDrawDC = pDC;
    CBitmap bitmap;
    CBitmap* pOldBitmap = 0;

    // only paint the rect that needs repainting
    CRect client;
    pDC->GetClipBox(client);
    CRect rect = client;
    DocToClient(rect);

    if (!pDC->IsPrinting())
    {
    // draw to offscreen bitmap for fast looking repaints
    if (dc.CreateCompatibleDC(pDC))
    {
    if (bitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height()))
    {
    OnPrepareDC(&dc, NULL);
    pDrawDC = &dc;

    // offset origin more because bitmap is just piece of the whole drawing
    dc.OffsetViewportOrg(-rect.left, -rect.top);
    pOldBitmap = dc.SelectObject(&bitmap);
    dc.SetBrushOrg(rect.left % 8, rect.top % 8);

    // might as well clip to the same rectangle
    dc.IntersectClipRect(client);
    }
    }
    }

    // paint background
    CBrush brush;
    if (!brush.CreateSolidBrush(pDoc->GetPaperColor()))
    return;

    brush.UnrealizeObject();
    pDrawDC->FillRect(client, &brush);

    if (!pDC->IsPrinting() && m_bGrid)
    DrawGrid(pDrawDC);

    pDoc->Draw(pDrawDC, this);

    if (pDrawDC != pDC)
    {
    pDC->SetViewportOrg(0, 0);
    pDC->SetWindowOrg(0,0);
    pDC->SetMapMode(MM_TEXT);
    dc.SetViewportOrg(0, 0);
    dc.SetWindowOrg(0,0);
    dc.SetMapMode(MM_TEXT);
    pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(),
    &dc, 0, 0, SRCCOPY);
    dc.SelectObject(pOldBitmap);
    }
    }

Discussions similaires

  1. Comment faire pour déplacer un enregistrement?
    Par steeves5 dans le forum Access
    Réponses: 2
    Dernier message: 15/06/2006, 14h13
  2. Réponses: 3
    Dernier message: 11/05/2006, 11h32
  3. Réponses: 3
    Dernier message: 27/04/2006, 12h24
  4. [TP]Pour faire un rectangle
    Par Bruce Campbell dans le forum Turbo Pascal
    Réponses: 8
    Dernier message: 14/10/2003, 15h37

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo