web-dev-qa-db-fra.com

Colore différentes parties d'une chaîne RichTextBox

J'essaie de colorer des parties d'une chaîne à ajouter à un RichTextBox. J'ai une chaîne construite à partir de différentes chaînes.

string temp = "[" + DateTime.Now.ToShortTimeString() + "] " +
              userid + " " + message + Environment.NewLine;

Voici à quoi ressemblerait le message une fois qu’il sera construit.

[21h23] Utilisateur: mon message ici.

Je veux que tout ce qui est compris entre les crochets [9:23] soit d'une couleur, "utilisateur" d'une autre couleur et le message d'une autre couleur. Ensuite, j'aimerais que la chaîne soit ajoutée à ma RichTextBox.

Comment puis-je accomplir cela?

96
Fatal510

Voici une méthode d'extension qui surcharge la méthode AppendText avec un paramètre color:

public static class RichTextBoxExtensions
{
    public static void AppendText(this RichTextBox box, string text, Color color)
    {
        box.SelectionStart = box.TextLength;
        box.SelectionLength = 0;

        box.SelectionColor = color;
        box.AppendText(text);
        box.SelectionColor = box.ForeColor;
    }
}

Et voici comment vous l'utiliseriez:

var userid = "USER0001";
var message = "Access denied";
var box = new RichTextBox
              {
                  Dock = DockStyle.Fill,
                  Font = new Font("Courier New", 10)
              };

box.AppendText("[" + DateTime.Now.ToShortTimeString() + "]", Color.Red);
box.AppendText(" ");
box.AppendText(userid, Color.Green);
box.AppendText(": ");
box.AppendText(message, Color.Blue);
box.AppendText(Environment.NewLine);

new Form {Controls = {box}}.ShowDialog();

Notez que vous remarquerez peut-être des scintillements si vous envoyez beaucoup de messages. Voir ce coin C # article pour des idées sur la façon de réduire le scintillement RichTextBox.

217
Nathan Baulch

J'ai développé la méthode avec la police comme paramètre:

public static void AppendText(this RichTextBox box, string text, Color color, Font font)
{
    box.SelectionStart = box.TextLength;
    box.SelectionLength = 0;

    box.SelectionColor = color;
    box.SelectionFont = font;
    box.AppendText(text);
    box.SelectionColor = box.ForeColor;
}
11
Renan F.

Ceci est la version modifiée que j'ai mise dans mon code (j'utilise .Net 4.5) mais je pense que cela devrait fonctionner également sur la version 4.0.

public void AppendText(string text, Color color, bool addNewLine = false)
{
        box.SuspendLayout();
        box.SelectionColor = color;
        box.AppendText(addNewLine
            ? $"{text}{Environment.NewLine}"
            : text);
        box.ScrollToCaret();
        box.ResumeLayout();
}

Différences avec l'original:

  • possibilité d'ajouter du texte à une nouvelle ligne ou simplement de l'ajouter
  • pas besoin de changer de sélection, ça marche pareil
  • inséré ScrollToCaret pour forcer le défilement automatique
  • ajout de suspendre/reprendre les appels de mise en page
7
tedebus

Je pense que modifier un "texte sélectionné" dans un RichTextBox n'est pas la bonne façon d'ajouter du texte coloré . Voici donc une méthode pour ajouter un "bloc de couleur"

        Run run = new Run("This is my text");
        run.Foreground = new SolidColorBrush(Colors.Red); // My Color
        Paragraph paragraph = new Paragraph(run);
        MyRichTextBlock.Document.Blocks.Add(paragraph);

De MSDN :

La propriété Blocks est la propriété content de RichTextBox. C'est un collection d'éléments de paragraphe. Contenu dans chaque élément de paragraphe peut contenir les éléments suivants: 

  • En ligne

  • InlineUIContainer

  • Courir

  • Span

  • Audacieux

  • Lien hypertexte

  • Italique

  • Souligner

  • Saut de ligne

Je pense donc que vous devez diviser votre chaîne en fonction de la couleur des pièces et créer autant d'objets Run que nécessaire.

3
Elo

C'est un travail pour moi! J'espère que cela vous sera utile!

public static RichTextBox RichTextBoxChangeWordColor(ref RichTextBox rtb, string startWord, string endWord, Color color)
{
    rtb.SuspendLayout();
    Point scroll = rtb.AutoScrollOffset;
    int slct = rtb.SelectionIndent;
    int ss = rtb.SelectionStart;
    List<Point> ls = GetAllWordsIndecesBetween(rtb.Text, startWord, endWord, true);
    foreach (var item in ls)
    {
        rtb.SelectionStart = item.X;
        rtb.SelectionLength = item.Y - item.X;
        rtb.SelectionColor = color;
    }
    rtb.SelectionStart = ss;
    rtb.SelectionIndent = slct;
    rtb.AutoScrollOffset = scroll;
    rtb.ResumeLayout(true);
    return rtb;
}

public static List<Point> GetAllWordsIndecesBetween(string intoText, string fromThis, string toThis,bool withSigns = true)
{
    List<Point> result = new List<Point>();
    Stack<int> stack = new Stack<int>();
    bool start = false;
    for (int i = 0; i < intoText.Length; i++)
    {
        string ssubstr = intoText.Substring(i);
        if (ssubstr.StartsWith(fromThis) && ((fromThis == toThis && !start) || !ssubstr.StartsWith(toThis)))
        {
            if (!withSigns) i += fromThis.Length;
            start = true;
            stack.Push(i);
        }
        else if (ssubstr.StartsWith(toThis) )
        {
            if (withSigns) i += toThis.Length;
            start = false;
            if (stack.Count > 0)
            {
                int startindex = stack.Pop();
                result.Add(new Point(startindex,i));
            }
        }
    }
    return result;
}
1

À l'aide de Selection dans WPF, en regroupant plusieurs autres réponses, aucun autre code n'est requis (à l'exception de Severity enum et de la fonction GetSeverityColor).

 public void Log(string msg, Severity severity = Severity.Info)
    {
        string ts = "[" + DateTime.Now.ToString("HH:mm:ss") + "] ";
        string msg2 = ts + msg + "\n";
        richTextBox.AppendText(msg2);

        if (severity > Severity.Info)
        {
            int nlcount = msg2.ToCharArray().Count(a => a == '\n');
            int len = msg2.Length + 3 * (nlcount)+2; //newlines are longer, this formula works fine
            TextPointer myTextPointer1 = richTextBox.Document.ContentEnd.GetPositionAtOffset(-len);
            TextPointer myTextPointer2 = richTextBox.Document.ContentEnd.GetPositionAtOffset(-1);

            richTextBox.Selection.Select(myTextPointer1,myTextPointer2);
            SolidColorBrush scb = new SolidColorBrush(GetSeverityColor(severity));
            richTextBox.Selection.ApplyPropertyValue(TextElement.BackgroundProperty, scb);

        }

        richTextBox.ScrollToEnd();
    }
0
Honza Nav
private void Log(string s , Color? c = null)
        {
            richTextBox.SelectionStart = richTextBox.TextLength;
            richTextBox.SelectionLength = 0;
            richTextBox.SelectionColor = c ?? Color.Black;
            richTextBox.AppendText((richTextBox.Lines.Count() == 0 ? "" : Environment.NewLine) + DateTime.Now + "\t" + s);
            richTextBox.SelectionColor = Color.Black;

        }
0
KhaledDev

En sélectionnant le texte comme dit de quelqu'un, la sélection peut apparaître momentanément . Dans Windows Forms applications, il n'y a pas d'autre solution au problème, mais aujourd'hui, j'ai trouvé une mauvaise façon de résoudre le problème: vous pouvez mettre une PictureBox en chevauchement avec la RichtextBox avec la capture d'écran de if, lors de la sélection et du changement de couleur ou de police, en la faisant réapparaître après tout, lorsque l'opération est terminée.

Le code est là ...

//The PictureBox has to be invisible before this, at creation
//tb variable is your RichTextBox
//inputPreview variable is your PictureBox
using (Graphics g = inputPreview.CreateGraphics())
{
    Point loc = tb.PointToScreen(new Point(0, 0));
    g.CopyFromScreen(loc, loc, tb.Size);
    Point pt = tb.GetPositionFromCharIndex(tb.TextLength);
    g.FillRectangle(new SolidBrush(Color.Red), new Rectangle(pt.X, 0, 100, tb.Height));
}
inputPreview.Invalidate();
inputPreview.Show();
//Your code here (example: tb.Select(...); tb.SelectionColor = ...;)
inputPreview.Hide();

Mieux vaut utiliser WPF; cette solution n'est pas parfaite, mais pour Winform, cela fonctionne.

0
user6730329