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

Windows Forms Discussion :

[C#]Changer couleur d'une partie d'un texte


Sujet :

Windows Forms

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre très actif
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    612
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juin 2008
    Messages : 612
    Par défaut [C#]Changer couleur d'une partie d'un texte
    Bonjour,

    Voici mon problème :
    Je dois écrire (entre autres) un texte dans la méthode OnPaint(PaintEventArgs e)

    Jusque là, pas de problème avec e.Graphics.DrawString que j'utilise souvent.

    Ensuite, je dois sélectionner une partie du texte, et donc entourer cette partie d'un rectangle bleu. Ici non plus, pas de problème, j'utilise les régions, comme ceci dans cet extrait que j'ai simplifié pour mes tests :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    gfx.DrawString(text, Font, brushFore, posX, posY);
     
    var charRanges = new CharacterRange[]                                       // créer un tableau de Zones de texte
      { new CharacterRange(selectionStart, 1) };                                  // une seule zone, la zone sélectionnée
    sf.SetMeasurableCharacterRanges(charRanges);                                // lie le stringFormat aux zones de texte
    var regions = gfx.MeasureCharacterRanges(text, Font, ClientRectangle, sf);  // obtient toutes les régions des zones textes (1 seule ici)
    gfx.FillRegion(brushbackselect, regions[0]);                                // colorie le fond du texte sélectionné
    var rec = regions[0].GetBounds(gfx);                                        // récupère le rectangle de la région
    Là où ça se gâte, c'est lorsque je dois réécrire la partie masquée de la chaîne avec une couleur contrastante avec ce rectangle, et là, mission impossible avec :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    gfx.DrawString(text.Substring(selectionStart, 1), Font, brushforeselect, rec, sf);
    Parce qu'avec un seul caractère sélectionné (ici, selectionLenght est forcé partout à 1) ce caractère s'affiche bien, mais par à l'exacte position correcte, il est décalé d'un ou deux pixels (souvent vers le bas et la droite) en fonction de la fonte utilisée.

    De plus, si je sélectionne 2 caractères ou plus, alors 1 seul s'affiche car il manque quelques pixels pour afficher le second, bien que le rectangle bleu recouvre correctement les 2 caractères à remplacer. Je suis contraint d'élargir le rectangle d'une taille dépendant de la largeur de la fonte, et donc non reproductible, et évidemment mes caractères réaffichés souffrent du même problème de non alignement.

    J'ai évidemment cherché dans la MSDN, mais justement ils fournissent des exemples qui opèrent avec la première partie du code que j'affiche, mais en utilisant une couleur semi-transparence, ce qui leur évite de devoir réécrire la portion de texte masquée, et donc de dévoiler ce problème. Comme quoi ils ont forcément remarqué le dit problème.

    Bref, quelqu'un a-t-il un moyen pour réécrire une portion de chaine sur un texte avec une autre couleur en superposant exactement cette portion à son emplacement d'origine?

    Ou, autre solution, comment écrire un texte de 2 couleurs différentes?

    J'ai bien pensé à transformer le rectangle concerné en bitmap et changer la couleur de chaque pixel trouvé, mais ça me semble excessivement lourd.

    Merci d'avance,
    Claude

  2. #2
    Expert confirmé

    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Septembre 2006
    Messages
    3 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Chef de projet NTIC
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Septembre 2006
    Messages : 3 580
    Par défaut
    le code suivant fait ce que tu demandes me semble t-il

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
            private void Form1_Paint(object sender, PaintEventArgs e)
            {
                Graphics g = e.Graphics;
     
                SolidBrush br1 = new SolidBrush(Color.LightBlue);
                SolidBrush br2 = new SolidBrush(Color.Red);
     
                SizeF t1 = g.MeasureString("nico", Font, new PointF(0, 10), StringFormat.GenericTypographic);
                SizeF t2 = g.MeasureString("las", Font);
                g.DrawString("nico", Font, br1, new PointF(0, 10));
                g.DrawString("las", Font, br2, new PointF(t1.Width, 10));
                g.DrawString("nicolas", Font, br1, new PointF(0, 40));
            }

  3. #3
    Membre très actif
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    612
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juin 2008
    Messages : 612
    Par défaut
    le code suivant fait ce que tu demandes me semble t-il
    Effectivement, et ton exemple fonctionnel m'a permis de trouver ce qui ne fonctionnait pas dans mon code, dont les paramètres de StringFormat. Merci

    Je profite de ta syntaxe pour poser une question subsidiaire (malheureusement, aucun prix à gagner) :

    Quand on utilise cette syntaxe :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    var dim = g.MeasureString("nico", Font, new PointF(0, 10), StringFormat.GenericTypographic);
    ou de façon plus générale, celle-ci (monObjet étant un objet IDisposable) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MaMethode (new monObjet());
    L'objet est-il disposé automatiquement ou non après l'appel de la méthode ou simplement plus référencé?

    Autrement dit les deux syntaxes précédentes sont-elles équivalentes à ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    using (var sf = StringFormat.GenericTypographic)
    using (var obj = new monObjet())
    {
       var dim = g.MeasureString("nico", Font, new PointF(0, 10), sf);
        MaMethode(obj);
    }
    ?
    C'est une question qui me préoccupe un peu, je n'ai rien trouvé à ce sujet dans les documentations sur Dispose().
    Pour l'instant, dans le doute, j'utilise systématiquement la seconde méthode (ou .Dispose()), pour ne pas laisser trainer des objets non disposés après usage.

    Merci

  4. #4
    Expert confirmé

    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Septembre 2006
    Messages
    3 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Chef de projet NTIC
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Septembre 2006
    Messages : 3 580
    Par défaut
    de toute façon, ton objet sera dégagé par le GC (garbage collector) si il n'est plus utilisé ni référencé

    Pour moi, le fait de faire un dispose() aide "grandement" le GC à éviter d'avoir à chercher ce qu'il doit dégager car en faisant dispose(), tu lui dis, "tiens, cet objet, tu peux le poubelliser sans problème"... avantage important puisque celà lui evitera d'avoir à chercher quoi nettoyer

    C'est pourquoi, par exemple, quand on crée des Brush, des Pen(s) etc..; il est conseillé de les disposer pour gagner en performance plutot que de laisser le GC à un moment nettoyer tout en prenant plus de temps qu'avec le Dispose().

    En aucun cas, tu n'auras de Memory Leak.. mais avec le dispose() tu éviteras les montées dans les tours de ta mémoire

  5. #5
    Membre très actif
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    612
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juin 2008
    Messages : 612
    Par défaut
    Oui, j'avais bien compris le mécanisme de Dispose et aussi comment l'implémenter. A ce niveau, je n'ai aucun problème particulier, j'ai lu pas mal de docs à ce sujet.

    J'ai bien compris (je pense) qu'il faut appeler dispose pour tous les objets IDisposable, et également comment implémenter l'interface IDisposable, ainsi qu'un finaliseur de sécurité pour les ressources non managées dans l'objet de base.

    Ce que je voulais savoir c'est si lorsque j'écris

    MaMethode (new MonObjet());

    Donc, en créant l'objet "MonObjet" sans lui donner de nom explicite directement dans les paramètres passés à ma méthode, ou lorsqu'on obtient une instance dans les paramètres, comme tu l'as fait avec StringFormat.GenericTypographic (qui crée en fait une instance avec des valeurs par défaut),

    l'objet est-il disposé automatiquement par le code compilé final, ou "oublié" et donc laissé à disposition du GC mais sans libérer de suite ses ressources?

    Parce que si la réponse est non, ça veut dire qu'il ne faudrait donc jamais pour bien faire utiliser cette syntaxe avec des objets IDisposables, puisqu'on ne dispose bien évidemment d'aucun nom d'instance pour les libérer ensuite, et que donc on se fierait alors uniquement au GC avec tous les désagréments que ça occasionne.

    Dit de façon résumée, si ceci est toujours correct :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MaMéthode (new ObjetNonDisposable()); // Pas besoin de Dispose, la question ne se pose pas
    est-ce que ceci l'est ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MaMethode (new ObjetDisposable()); // l'objet est-il correctement disposé?
    J'espère que dit comme ça, ma question est plus claire

  6. #6
    Membre Expert Avatar de Guulh
    Homme Profil pro
    Inscrit en
    Septembre 2007
    Messages
    2 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2007
    Messages : 2 160
    Par défaut
    Citation Envoyé par ClaudeBg Voir le message
    est-ce que ceci l'est ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MaMethode (new ObjetDisposable()); // l'objet est-il correctement disposé?
    Non, il ne l'est pas. Son finaliseur sera appelé à un moment ou à un autre, mais la méthode dispose n'est jamais appelée automatiquement.

    Donc oui, un objet Disposable qui n'a vocation qu'à passer en paramètre d'une méthode doit tout de même être disposé (que ce soit avec un bloc using ou un appel explicite, of course), ce qui donne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    using(ObjetDisposable d = new ObjetDisposable())
        MaMethode(d);
    Et tant que j'y suis, Dispose n'a rien à voir avec la mémoire La mémoire, le framework la gère tout seul. Dispose sert à libérer d'autres types de ressources, comme des connexions réseaux, des fichiers, des handles, ...
    Et éventuellement de la mémoire si t'en avais alloué à la main (en interop par exemple), mais il y a peu souvent des raisons de le faire, dans notre beau monde managé.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 2
    Dernier message: 26/04/2010, 15h36
  2. changer la couleur d'une partie d'une chaine de caractère
    Par mohcultiv dans le forum Général JavaScript
    Réponses: 10
    Dernier message: 18/01/2008, 00h16
  3. Réponses: 1
    Dernier message: 12/09/2007, 18h11
  4. [TTrackbar] Changer couleur de la partie selected
    Par MiJack dans le forum Delphi
    Réponses: 7
    Dernier message: 13/11/2006, 13h16
  5. changer couleur d'une "case" selon clique
    Par Jéjé2reims dans le forum MFC
    Réponses: 4
    Dernier message: 05/02/2004, 12h19

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