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 :

BitBlit/Stretchblit pour une boite de dialogue?


Sujet :

MFC

  1. #1
    Membre du Club
    Inscrit en
    Juin 2004
    Messages
    79
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 79
    Points : 46
    Points
    46
    Par défaut BitBlit/Stretchblit pour une boite de dialogue?
    Bonjour à tous,

    Je dessine sur une boite de dialogue simple. Et en rafraichissant la boite, j'obtiens un effet de scintillement. Dans le cas d'une CView, j'utilisais ce qu'on appelle je crois le double buffer: dessiner dans un DC compatible avec le DC de la cview puis faire un StrechBlt ou un BitBlt.

    J'ai donc naturellement voulu appliquer le même principe dans le cas de dessins dans ma boite de dialogue...mais cela ne fonctionne pas

    Mon code est le suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    CDC* pDC;
    CDC DC;
    CRect myRect;
     
    pDC=this->GetDC();
    this->GetClientRect(&myRect);
    DC.CreateCompatibleDC(pDC);
     
    DC.MoveTo(10,10);
    DC.LineTo(20,20);
     
    pDC->BitBlt(0,0,myRect.Width(),myRect.Height(),&DC,0,0,SRCCOPY);
    Que je mette ce code dans le OnPaint, Dans le BN_CLICK d'un bouton, rien n'y fait, je n'ai rien à l'écran...

    Qqn aurait-il une suggestion?
    Merci d'avance!

  2. #2
    Rédacteur
    Avatar de farscape
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2003
    Messages
    9 055
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2003
    Messages : 9 055
    Points : 17 323
    Points
    17 323
    Par défaut
    salut,
    le bouton doit etre owner draw et la methode de dessin dans drawitem,
    comme cet exemple de la faq:
    http://c.developpez.com/faq/vc/?page...awBitmapInCtrl

  3. #3
    Membre du Club
    Inscrit en
    Juin 2004
    Messages
    79
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 79
    Points : 46
    Points
    46
    Par défaut
    Citation Envoyé par farscape
    salut,
    le bouton doit etre owner draw et la methode de dessin dans drawitem,
    comme cet exemple de la faq:
    http://c.developpez.com/faq/vc/?page...awBitmapInCtrl
    Désolé, mais je ne comprends pas le lien avec mon problème... Peux-tu me donner un exemple?
    DrawItem ne permet-il pas de dessiner à l'intérieur d'un contrôle ?
    Ce que je voudrai faire c'est dessiner directement dans la boite de dialogue... avec un getDC(), je peux récupérer le DC de la boite et dessiner... mais j'ai un problème quand je souhaite utiliser StretchBlt...

    Pour en dire un peu plus, en fait, j'affiche dans une boite de dialogue un diagramme (Y=f(X)) et la courbe doit évoluer à travers le temps, du coup à chaque fois le OnPaint() réaffiche TOUTE la boite, et (en particulier), les axes clignotent...
    J'ai essayé de chercher du coté du OnEraseBckground mais là, si je fais un return FALSE à l'intérieur de cette méthode, j'ai dans la boite de dialogue les courbes successives qui s'affichent...

    Si qqn a une solution...
    Merci d'avance

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    195
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 195
    Points : 82
    Points
    82
    Par défaut
    Salut TigreRouge

    Si tu veux simplement dessiner un rectangle dans ta fenêtre tu peux amplement te passer d'un device context jouant le rôle de buffer et d'un appel à la méthode Bitblt(....).

    fait simplement, dans OnDraw(CDC* pDC):

    void OnDraw(CDC* pDC){
    pDC->Rectangle(x,y, x1,y1);
    }

    Si tu veux placer ton code graphique autre part que dans OnDraw(),
    fait:
    ex: ta fonction xxx appartient à l'objet par défaut CView créé par MFC

    void fonction_perso(){
    CDC* DC_Ecran = GetDC();
    DC_Ecran->Rectangle(x,y, x1,y1);
    }

    ATTENTION: quand tu fait "GetDC()" le DC que tu reçoit est temporaire !!!!!!
    A la prochaine boucle, c'est un autre DC toujours de la fenetre principale que tu va recevoir dans une variable de ton choix, donc évite ABSOLUMENT ce cas là:

    (tu peux tester ca cas, ca va faire n'importe quoi et le résultat est logique car le 2ème appel à GetDC() remet tout à ZERO. Donc, ton MoveTo est annulé et le départ de ta droite se situe à {0,0} par défaut)
    void fonction_xxx(){
    GetDC()->MoveTo(x,y);
    GetDC()->LineTo(x1,y1);
    }

    Adopte plutôt celui-ci:

    void fonction_xxx(){
    TempDC = GetDC();
    TempDC->MoveTo(x,y);
    TempDC->LineTo(x1,y1);
    }

    PS: la méthode BitBlt est bien choisie si tu doit traiter un nombre astronomique de rectangle et de ligne.
    Procède alors comme tu as fait : déssine tout dans un DC "de stockage" et remplie le contenu dans le DC écran.

    J'espère que cela va t'aiter et répond à ton problème....
    Séb.

  5. #5
    Membre du Club
    Inscrit en
    Juin 2004
    Messages
    79
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 79
    Points : 46
    Points
    46
    Par défaut
    Bonsoir Cyber_N,

    Merci pour ton aide.
    Cependant, j'essaye de passer par BitBlit car je réaffiche souvent ma boite de dialogue (car courbe successive dans mon diagramme Y=f(X)) et à chaque fois, cela me fait un effet de flash, scintillement désagréable. Lorsque je dessine dans une CView, je dessine dans un CDC compatible et je bitblit... mais mon problème est qu'avec une boite de dialogue simple, le bitblit entre un CDC mémoire et le DC récupéré de la boite de dialogue ne semble pas fonctionner...

    S'il y a une autre solution pour éviter le "scintillement" que de passer par un bitblit (que je n'arrive pas à faire marcher), je suis évidemment preneur...

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    195
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 195
    Points : 82
    Points
    82
    Par défaut
    Ok! Je vois.

    Pour essayer de comprendre et cerner ton problème:
    Pour faire plus simple, envoie moi juste les phrases qui suivent avec un signe OK ou NON ou OUI, .....
    est ce que:

    -> TOUT ton code graphique est dans OnDraw()
    -> tu utilises la fonction InvalidateRect(true); pour nettoyer l'écran
    -> tu utilises Invalidate()
    -> tu utilises un bitmap vierge de stockage associé à ton CDC.

    Ce que j'essaie de comprendre, c'est COMMENT TU EFFACES l'écran pour redessiner ensuite.... sinon je crois que j'ai compris. mais il me faut ces indications pour pouvoir te répondre.

    a++;

  7. #7
    Membre du Club
    Inscrit en
    Juin 2004
    Messages
    79
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 79
    Points : 46
    Points
    46
    Par défaut
    Citation Envoyé par cyber_N
    ->TOUT ton code graphique est dans OnDraw()
    Non. Je n'ai pas de méthode OnDraw() mais une méthode OnPaint() dans lequel en effet, j'ai mon code graphique.

    Citation Envoyé par cyber_N
    -> tu utilises la fonction InvalidateRect(true); pour nettoyer l'écran
    Non.
    Citation Envoyé par cyber_N
    -> tu utilises Invalidate()
    Oui. En fait, j'ai un évènement OnMouseMove qui repère les mouvements de la souris et dans cette évènement, j'ai un this->Invalidate(). Si j'ai bien compris, cela apelle le code dans le OnPaint() qui appelle automatiquement OnEraseBkgnd(CDC* pDC) qui, lui, par défaut "peint" la boite avec un CBrush par défaut.
    Citation Envoyé par cyber_N
    -> tu utilises un bitmap vierge de stockage associé à ton CDC.
    : : Pas compris la question...

    Citation Envoyé par cyber_N
    Ce que j'essaie de comprendre, c'est COMMENT TU EFFACES l'écran pour redessiner ensuite....
    J'imagine que c'est le OnPaint() qui automatiquement appelle OnEraseBkgnd()... Corrigez moi si je me trompe...

  8. #8
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    38
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2005
    Messages : 38
    Points : 40
    Points
    40
    Par défaut
    Bonjour,

    Est-ce que tu as le même résultat de clignotement si tu utilises l'objet CPaintDC dans ta méthode OnPaint.

    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 CMaDlg::OnPaint()
    {
       CPaintDC DC(this);
       CDC DCMem; 
       CRect myRect; 
     
       this->GetClientRect(&myRect); 
       DCMem.CreateCompatibleDC(&DC); 
     
       DCMem.MoveTo(10,10); 
       DCMem.LineTo(20,20); 
     
       DC.BitBlt(0,0,myRect.Width(),myRect.Height(),&DCMem,0,0,SRCCOPY);
    }

  9. #9
    Membre du Club
    Inscrit en
    Juin 2004
    Messages
    79
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 79
    Points : 46
    Points
    46
    Par défaut
    Citation Envoyé par Madeiras
    Bonjour,

    Est-ce que tu as le même résultat de clignotement si tu utilises l'objet CPaintDC dans ta méthode OnPaint.

    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 CMaDlg::OnPaint()
    {
       CPaintDC DC(this);
       CDC DCMem; 
       CRect myRect; 
     
       this->GetClientRect(&myRect); 
       DCMem.CreateCompatibleDC(&DC); 
     
       DCMem.MoveTo(10,10); 
       DCMem.LineTo(20,20); 
     
       DC.BitBlt(0,0,myRect.Width(),myRect.Height(),&DCMem,0,0,SRCCOPY);
    }
    Ce code malheureusement ne m'affiche pas le trait...
    Mais quand je remplace
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
       DCMem.MoveTo(10,10); 
       DCMem.LineTo(20,20);
    par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    DC.MoveTo(10,10); 
     DC.LineTo(20,20);
    , cad quand j'affiche directement sur le DC de la boite, là, ca marche...Ce qui me fait penser que le bitblit ne fonctionne pas correctement
    C'est d'autant plus étrange que je ne trouve aucun problème de ce type en cherchant sur le net... je vais craquer...

  10. #10
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    38
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2005
    Messages : 38
    Points : 40
    Points
    40
    Par défaut
    Autre solution possible,

    Tu ajoutes un contrôle CStatic dans ta boîte de dialogue, tu peux par programmation t'arranger pour que ce contrôle s'adapte à la taille de la zone cliente de la dlg.

    Ensuite, tu dessines dans le DC du CStatic, avec tes instructions de double buffer, et avec l'espoir d'effacer l'effet de scintillement lors de l'affichage. (Il ne faut plus dessiner dans le DC de la dlg).

    Je me rappel qu'en DOS, lorsque je dessinais du graphique, j'utilisais la technique du wait retrace afin d'attendre le balayage de l'écran pour dessiner sans effet de clignotement, mais je ne sais pas si c'est toujours d'actualité sous Windows. Et si oui, je ne sais pas si les instructions assembler que j'utilisais pourraient encore fonctionner.

  11. #11
    Membre du Club
    Inscrit en
    Juin 2004
    Messages
    79
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 79
    Points : 46
    Points
    46
    Par défaut
    Citation Envoyé par Madeiras
    Autre solution possible,

    Tu ajoutes un contrôle CStatic dans ta boîte de dialogue, tu peux par programmation t'arranger pour que ce contrôle s'adapte à la taille de la zone cliente de la dlg.

    Ensuite, tu dessines dans le DC du CStatic, avec tes instructions de double buffer, et avec l'espoir d'effacer l'effet de scintillement lors de l'affichage. (Il ne faut plus dessiner dans le DC de la dlg).

    Je me rappel qu'en DOS, lorsque je dessinais du graphique, j'utilisais la technique du wait retrace afin d'attendre le balayage de l'écran pour dessiner sans effet de clignotement, mais je ne sais pas si c'est toujours d'actualité sous Windows. Et si oui, je ne sais pas si les instructions assembler que j'utilisais pourraient encore fonctionner.
    Oui, même si la solution CStatic fait un peu bricolage, je vais quand même l'essayer demain vu que je suis dans l'impasse pour le moment. Merci pour ton aide Madeiras
    Sinon, je continue à essayer de chercher de la doc mais apparemment le double buffering devrait fonctionner sur une CDialog (il y a des exemples sur le net avec des bitmap qu'on affiche sur la boite..mais pourquoi une pauvre ligne refuse de s'afficher... T_T )

  12. #12
    Rédacteur
    Avatar de farscape
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2003
    Messages
    9 055
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2003
    Messages : 9 055
    Points : 17 323
    Points
    17 323
    Par défaut
    salut,
    aucun probleme pourtant !
    rapidement :
    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
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
     
    #if !defined(AFX_MYBUTTON_H__0EFA9690_5DE5_4E5F_B0ED_F2AEF9E652F5__INCLUDED_)
    #define AFX_MYBUTTON_H__0EFA9690_5DE5_4E5F_B0ED_F2AEF9E652F5__INCLUDED_
     
    #if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000
    // Mybutton.h : header file
    //
    /////////////////////////////////////////////////////////////////////////////
    // CMybutton window
     
    class CMybutton : public CButton
    {
    // Construction
    public:
    	CMybutton();
     
    // Attributes
    public:
     
    // Operations
    public:
     
    // Overrides
    	// ClassWizard generated virtual function overrides
    	//{{AFX_VIRTUAL(CMybutton)
    	public:
    	virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
    	protected:	
    	virtual void PreSubclassWindow();
    	//}}AFX_VIRTUAL
     
    // Implementation
    public:
    	virtual ~CMybutton();
     
    	// Generated message map functions
    protected:
    	//{{AFX_MSG(CMybutton)
     
    	//}}AFX_MSG
     
    	DECLARE_MESSAGE_MAP()
    };
    /////////////////////////////////////////////////////////////////////////////
    //{{AFX_INSERT_LOCATION}}
    // Microsoft Visual C++ will insert additional declarations immediately before the previous line.
    #endif // !defined(AFX_MYBUTTON_H__0EFA9690_5DE5_4E5F_B0ED_F2AEF9E652F5__INCLUDED_)
     
    // .cpp
    #include "Mybutton.h"
     
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
     
    /////////////////////////////////////////////////////////////////////////////
    // CMybutton
     
    CMybutton::CMybutton()
    {
    }
     
    CMybutton::~CMybutton()
    {
    }
     
     
    BEGIN_MESSAGE_MAP(CMybutton, CButton)
    	//{{AFX_MSG_MAP(CMybutton)
     
    	//}}AFX_MSG_MAP
    END_MESSAGE_MAP()
     
    /////////////////////////////////////////////////////////////////////////////
    // CMybutton message handlers
    void CMybutton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 
    {
    	// TODO: Add your code to draw the specified item
        ASSERT(lpDrawItemStruct != NULL);
        CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
        //UINT nState = lpDrawItemStruct->itemState;
        CRect itemRect = lpDrawItemStruct->rcItem;
     
        CDC MemDC;
        MemDC.CreateCompatibleDC(pDC);
        CBitmap bmp;
        bmp.CreateCompatibleBitmap(&MemDC,itemRect.Width(),itemRect.Height());  
        CBitmap *pOldBitmap =MemDC.SelectObject (&bmp);
     
        MemDC.PatBlt(0,0,itemRect.Width(),itemRect.Height(),WHITENESS);
     
        MemDC.MoveTo(10,10);
        MemDC.LineTo(20,20);
     
     
        pDC->BitBlt(0,0,itemRect.Width(),itemRect.Height(),&MemDC,0,0,SRCCOPY);
     
        MemDC.SelectObject (pOldBitmap);
    }
     
    void CMybutton::PreSubclassWindow() 
    {
    	// TODO: Add your specialized code here and/or call the base class
    	// Switch to owner-draw
        ModifyStyle(SS_TYPEMASK, BS_OWNERDRAW, SWP_FRAMECHANGED);
    	CButton::PreSubclassWindow();
    }

  13. #13
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    195
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 195
    Points : 82
    Points
    82
    Par défaut
    Bonjour à tous et toi TigreRouge.

    Voici pourquoi ton bitblt() ne marche pas ainsi que quelques conseils:

    CDC* pDC; // moi je mettrais: CDC* pDC = GetDC();
    CDC DC; // Ok !
    CRect myRect;

    pDC=this->GetDC(); // Ok ! tu n'a pas besoin de mettre this, à part si cela simplifie ta lecture....

    this->GetClientRect(&myRect);
    DC.CreateCompatibleDC(pDC); // Ok !


    // C'EST ICI QU'IL TE MANQUE UN TRUC INDISPENSABLE:
    // quand tu dessine dans ton CDC pour le déverser dans ton DC écran,
    // en fait tu dessine dans le vide! il faut une "planche à dessin" associé à // ton CDC temporaire, un HBITMAP vierge (blanc). (voir plus bas)


    DC.MoveTo(10,10); // Ok !
    DC.LineTo(20,20); // Ok !

    // essaie ici de mettre des valeurs fixes à la place de myRect
    // (je dit ça parce que j'ai eu des problèmes avec GetClientRect, mais si // tu es sûre des valeurs alors....ok)
    pDC->BitBlt(0,0,myRect.Width(),myRect.Height(),&DC,0,0,SRCCOPY);
    Voici ce qu'il te manque avant tout opérations graphique....
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    DC.CreateCompatibleDC( pDC );
    hBufferBitmap = CreateCompatibleBitmap(pDC, ecran_x, ecran_y);
    DC.SelectObject(hBufferBitmap);
    PS (pour le code ci-dessus): si "CreateCompatibleBitmap" te demande un HDC et non CDC comme type de variable, donne lui ca : "pDC->m_hDC".

    autre PS (pour Invalidate et le redessin à l'écran): ne place pas Invalidate() dans ton mousemove() mais appelle Invalidate() grâce à un timer. Si tu travailles avec les MFC crée avec ClassWisard un "OnTimer()" du message WM_TIMER et place un Invalidate() dans cette fonction OnTimer():

    #define NUM_TIMER 0
    void OnTimer(){
    Invalidate();
    SetTimer(NUM_TIMER, 25, NULL);
    }
    Lorsque tu demarres juste ton application fait SetTimer(NUM_TIMER, 25, NULL);

    Et voilà !
    [/quote]

Discussions similaires

  1. [Débutant] Ouvrir une boite de dialogue pour enregistrer un fichier
    Par pompier21 dans le forum Interfaces Graphiques
    Réponses: 2
    Dernier message: 09/10/2008, 10h09
  2. Réponses: 6
    Dernier message: 15/11/2007, 23h11
  3. Réponses: 3
    Dernier message: 02/10/2006, 16h45
  4. Réponses: 4
    Dernier message: 21/07/2006, 11h00
  5. Réponses: 6
    Dernier message: 14/06/2006, 08h56

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