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 :

[Avancé]Effacement d'une fonte alors quelle est sélectionnée


Sujet :

MFC

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2004
    Messages
    79
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2004
    Messages : 79
    Par défaut [Avancé]Effacement d'une fonte alors quelle est sélectionnée
    salut,

    Je vais essayer de simplifier le problème.

    Sur une source MS (http://support.microsoft.com/default.aspx?scid=kb;EN-US;q248496), j'ai trouvé un morceau de code me permettant, dans une TreeView, de desiner certaines lignes en gras (en l'occurrence, il s'agit ici des lignes ayant le focus)

    Voici le morceau de code permettant de faire ç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
     
                         {
     
                            HFONT hFont = (HFONT) ::SendMessage(hWndTreeView, WM_GETFONT, 0, 0);
     
                            LOGFONT lf = { 0 };
                            GetObject(hFont, sizeof(LOGFONT), &lf);
     
                            lf.lfWeight |= FW_BOLD;
    												//lf.lfHeight = 20;
     
                            HFONT hFontBold = CreateFontIndirect(&lf);
                            HFONT hOldFont = (HFONT) SelectObject(pNMTVCD->nmcd.hdc, hFontBold);
     
                            DeleteObject(hFontBold);
                         }
    Ce morceau de code est en fait exécuté à chaque fois que Windows repaint chacune des lignes de la TreeView (juste avant que la ligne soit repainte en fait => CDDS_ITEMPREPAINT)

    Donc, ici, le programme extrait la fonte du controle, lui applique un effet gras, et réapplique la fonte au DC du controle.

    Mais ce que je ne comprends pas, c'est ce DeleteObject(hFontBold); alors que la fonte est sélectionnée dans le DC du TreeView. Comment est ce possible? Ca me parait très bizarre (appels asynchrones?)

  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
    Par défaut
    salut,
    hum bizarre moi j'aurais fait le deleteObjet sur hOldFont.
    tu devrais regarder avec le gestionnaire des taches le nombre d'objets GDI alloués a ton application pour voir si il n'augmente pas en permanence sans redescendre

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2004
    Messages
    79
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2004
    Messages : 79
    Par défaut
    Bah faire un DeleteObject sur le hOldFont, ca ne doit pas servir à grand chose, vu que ca doit être un "objet systeme" (je ne sais pas si le terme est le bon), géré automatiquement, non?

    Par contre, je ne savais pas qu'il était possible de connaitre le nombre d'objets GDI alloués! Je viens de découvrir ça gracce à toi, c'est génial (car auparavant, je me demandais comment je pourrais faire pour savoir si j'avais des fuites du type GDI. Un outil du type "Process Viewer" ne me permettait pas vraiment de le faire)
    Bref, je regarde, et je te tiens au courant.

  4. #4
    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
    Par défaut
    ceci dis pour un tree view je te conseille cette solution tu fais ce que tu veux avec:
    http://www.developpez.net/forums/vie...691181#1691181

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2004
    Messages
    79
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2004
    Messages : 79
    Par défaut
    La solution que tu proposes est plutot astucieuse.

    Mais par contre, elle me dérange un petit peu, car elle demande au controle de tout dessiner, puis ensuite seulement de dessiner par dessus ce que l'on veut.

    Je ne peux bien sur pas mesurer la chose, mais je pense que ca peut se révéler relativement inefficace.Enfin, d'un point de vue conceptuel, c'est pas très propre. (on demande au controle de faire des choses qui ne serviront de toute manière à rien)

    Mais je note la solution, car elle est asucieuse.

    Sinon, j'ai as encore fait mes tests de décompte d'objets GDI.

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2004
    Messages
    79
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2004
    Messages : 79
    Par défaut
    Bon, je viens de faire mes tests, et donc, effectivement, le truc est bien codé, et le fait de faire un

    DeleteObject(hFontBold);
    permet de faire en sorte qu'il n'y ait pas de fuite mémoire en terme d'bjets GDI.

    Par contre, j'ai aussi testé avec un DeleteObject(hOldFont) et là, il y a bel et bien fuite mémoire GDI.

    Bref, je ne comprends pas bien pourquoi, mais bon, voici l'interpretation que je fais:


    Le DeleteObject(hFontBold); doit ête un appel synchrone (ce qui veut dire que l'effacement réel n'ets réalisé que pendant une boucle idle du processus), alors que le dessin du controle et les appels successifs du CustomDraw sont synchrones, et sont effectués de maniere ininterrompue...

    Mais bon, je ne m'explique pas comment il est possible d'effacer hFontBold sans l'extraire auparavant du dc...

  7. #7
    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
    Par défaut
    salut,
    Oui c'est bizarre tout ça ,ça doit s'appuyer sur une subtilité non décrite dans la doc ,
    autant dans le cas de CDC:SelectObject l'objet retourné est detruit dans la boucle OnIdle de CWinApp mais la .

    En ce qui concerne la solution évoquée,je l'utilise pour customiser une treeview avec checkbocx avec plusieurs couleurs par niveau avec le style xp ça fonctionne nickel.

    en fait tu modifies uniquement ce qui t'intéresse vu que l'on travaille sur un bitmap en mémoire.

    De toute façon vu qu'il n'y a pas de possibilités standards pour modifier les attributs du treeview j'ai pas trouvé mieux...



  8. #8
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2004
    Messages
    79
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2004
    Messages : 79
    Par défaut
    Très beau!

    Dans ta siuation, c'est vrai que, à part tout redessiner à la main (y compris les lignes entre les arborescences) tu n'as pas d'autre choix.

    Sinon, pour en revenir au CDC:SelectObject, comme un objet, s'il est détruit dans la boucle OnIdle, sait il qu'il n'est plus associé à aucun dc? (y a t il un reference counting quelque part ?)

    Où est ce que je pourrais trouver de la doc générale là dessus?

    Pour ce qui est du style XP, tu utilises des manifest pour avoir cet effet ombré? Là aussi, j'aurais aimé trouver de la doc.

  9. #9
    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
    Par défaut
    salut,
    en ce qui concerne la liberation de l'objet retourné par SelectObjet l'allusion est faite dans:
    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/_core_selecting_a_graphic_object_into_a_device_context.asp

    apres je crois qu'il faudra aller mettre le nez dans le code pour voir ce qui est fait

    oui j'utilise le manifest voir faq:
    http://c.developpez.com/faq/vc/?page...tXPStyleForApp
    et surtout post it faq:
    http://www.developpez.net/forums/vie...568587#1568587

    mais dans mon cas pour le treeview il s'agit de bitmap modifiés (a cause de la gestion de la couleur pour la coche).

  10. #10
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2004
    Messages
    79
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2004
    Messages : 79
    Par défaut
    Merci pour ces liens!

    En ce qui concerne les objets GDI et leur gestion, la doc MS est vraiment trop succinte! Bien sur, j'aurais aimé voir comment est fait le code, mais vu que c'est des appels API Windows, j'aurais un peu de mal...

    Mais bon, je viens de faire pas mal de tests, et pour pouvoir effacer un objet GDI, cela dépend de la situation:
    - S'il est sélectionné dans un DC, et qu'il n'est pas éjecté donc hors du DC, il faut faire deux choses: faire un DeletObject sur l'objet GDI et effacer le DC également (avec ReleaseDC ou DeleteDC selon les situations). Peu importe que le DeletObject soit fait avant ou après le ReleaseDC, l'objet GDI est bien effacé de la mémoire
    - Si l'objet GDI n'est pas ou plus sélectionné dans un DC, alors un DeleteObject sur l'objet GDI est suffisant.

    Ces tests sont donc conformes avec le code que je donnais plus haut (source MS): dans ce code, la fond bold est bel et bien effacée, même si elle n'est pas sélectionnée hors du DC par le code. Ca marche car il y a un DeleteObject et par ailleurs, je pense que le DC du controle est effacé (ou relâché)

    Voili.

  11. #11
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2004
    Messages
    79
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2004
    Messages : 79
    Par défaut
    Salut,

    Je continue donc dans la lancée du "custom draw" (même si mon choix final sera peut être du "dessin sur bitmap"), et je voulais savoir s'il m'était possible de changer de texte uniquement lorsque mon élément était sélectionné?

    En fait, j'ai essayéle code suivant dans le traitement du
    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
    NM_CUSTOMDRAW:
    	NMTVCUSTOMDRAW* pcd = (NMTVCUSTOMDRAW*) pNMHDR;
    	switch(pcd->nmcd.dwDrawStage){
    		case CDDS_PREPAINT:
    			*pResult = CDRF_NOTIFYITEMDRAW;
    			return;
    		case CDDS_ITEMPREPAINT:{
    			int i = pcd->nmcd.uItemState;
    			CString strTemp;
    			if ((pcd->nmcd.uItemState & CDIS_FOCUS) == CDIS_FOCUS){
    				HTREEITEM hItem = (HTREEITEM)pcd->nmcd.dwItemSpec;
    				TVITEM tvi = { 0 };
    				tvi.mask = TVIF_HANDLE | TVIF_TEXT;
    				tvi.hItem = hItem;
    				tvi.pszText="Selected";
    				::SendMessage(m_hWnd, TVM_SETITEM, 0, (LPARAM)&tvi);
    				//*pResult = CDRF_NEWFONT|CDRF_NOTIFYPOSTPAINT;
    			}
    			*pResult = CDRF_DODEFAULT;
    			return;
    		}
    		default:
    			*pResult = CDRF_DODEFAULT;
    	}
    Le problème ici est que dès que je sélectionne un élément de mon arbre, le texte change, mais par contre, ca scintille à fond. J'en déduis que par la suite, il y a des appels en boucle de ma fonction de traitement, mais pourquoi? Est que puis je faire pour éliminer cet effet?

  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
    Par défaut
    salut,
    difficile de repondre comme ça ,mais je dirais que le fait de changer le texte au moment du paint ,provoquera inevitablement un message de refresh ...
    essaye d'eviter de le faire systematiquement en commencant par regarder la valeur du texte en cours ..


  13. #13
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2004
    Messages
    79
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2004
    Messages : 79
    Par défaut
    Salut,

    Merci pour ta réponse.

    En fait, le but précis derrière tout ça est toujours le même: pouvoir écrire en gras.

    Je ne cherchais pas fondamentalement à changer de texte, mais à mieux comprendre comment le contrôle fonctionnait.
    le problème, quand je mets mon xte en gras (grace à la méthode citée au tout début), c'est que le texte déborde de la zone de dessin de l'item. Par exemple, imaginons que l'item est initialisé avec un "Bonjour" en non gras, j'ai l'impression que la taille prise par le Bonjour en non gras est calculée une fois pour toutes. Après, si je demande un "Bonjour" en gras, alors, inévitablement, il y a débordement...
    J'ai eu beau essayer avec un CDRF_NEWFONT, mais rien n'y fait...

    C'est vraiment difficile de travailler avec un controle aussi mal documenté, et de comprendre le fonctionnement interne de manière à le customiser un peu...

  14. #14
    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
    Par défaut
    Citation Envoyé par Yoyo@
    Salut,

    Merci pour ta réponse.

    En fait, le but précis derrière tout ça est toujours le même: pouvoir écrire en gras.

    Je ne cherchais pas fondamentalement à changer de texte, mais à mieux comprendre comment le contrôle fonctionnait.
    le problème, quand je mets mon xte en gras (grace à la méthode citée au tout début), c'est que le texte déborde de la zone de dessin de l'item. Par exemple, imaginons que l'item est initialisé avec un "Bonjour" en non gras, j'ai l'impression que la taille prise par le Bonjour en non gras est calculée une fois pour toutes. Après, si je demande un "Bonjour" en gras, alors, inévitablement, il y a débordement...
    J'ai eu beau essayer avec un CDRF_NEWFONT, mais rien n'y fait...

    C'est vraiment difficile de travailler avec un controle aussi mal documenté, et de comprendre le fonctionnement interne de manière à le customiser un peu...
    c'est en partie pour ça que j'ai opté pour la solution bitmap qui permet plus de souplesse au niveau customisation .
    les fonctionnalités de personnalisation du controle de base etant un peu trop "obscurs" a mon gout..

  15. #15
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2004
    Messages
    79
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2004
    Messages : 79
    Par défaut
    Obscur, c'est bien le mot... Surtout d'ailleurs our ce genre de controle! (pour une combo box, c'est par exemple bien plus clair, on gère le msg DRAWITEM, et c'est fini!...

    Sinon, j'ai une question qui n'a rien à voir, mais qui m'a été suscitée sur la méthode que tu m(indiquais pour détecter les fuites mémoire dues aux objets GDI Gestionnaire des taches Windows)

    Dans mon appli, je lance le code suivant:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
      HBRUSH hBr = ::CreateSolidBrush(RGB(255,0,0));
      ::DeleteObject(hBr);
    En théorie, ce code est propre.
    Ce que je ne comprends, c'est qu'à l'issue de la première passe (ce code est derrière un bouton de test), mon appli a un objet GDI en plus (cf Gestionnaire des taches) puis lorsque je le réexécute une fois encore, cette fois ci, il n'y a pas de nouvel objet GDI créé ni détruit. Est ce à dire que même si je demande la destruction du Brush lors de la première passe, il n'est pas réellement détruit?

Discussions similaires

  1. [PDO] requête traitée comme étant classique alors quelle est de PDO
    Par qqqqq dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 25/09/2010, 17h24
  2. Réponses: 1
    Dernier message: 29/03/2007, 14h46
  3. Réponses: 2
    Dernier message: 25/05/2005, 21h34
  4. Réponses: 11
    Dernier message: 31/01/2005, 17h48
  5. [MASM] Quelle est la longueur max d'une variable?
    Par Crisanar dans le forum Assembleur
    Réponses: 2
    Dernier message: 17/11/2004, 21h47

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