Richtextbox d'edition c# avec colorisation sytaxique

Soyez le premier à donner votre avis sur cette source.

Snippet vu 8 643 fois - Téléchargée 17 fois

Contenu du snippet

Bonjour, voici une class dérivé de RichTextBox servant d'editeur syntaxique C#

il prend en charge les mot clé , les commentaires //, les commentaire multiligne /**/
ainsi que les string "" ou @"" simple ou multiligne

il utilise TOM OBJECT MODEL pour mettre a jour les couleurs sans gener l'utilisateur

il y a un Thread qui est lancé Sur l'evenement OnTextChanged

Source / Exemple :


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using tom;
using System.Runtime.InteropServices;
using System.Threading;
using System.Text.RegularExpressions;
using System.Drawing;

namespace IrcChatClient.SpecificControls
{
    public class RichEditorCsharp : RichTextBox
    {
        private Thread th = null;

        public RichEditorCsharp()
        {
        }

        #region WIN32

        [DllImport("User32.dll")]
        public static extern int SendMessage(IntPtr hWnd, int message, IntPtr wParam, out IntPtr lParam);

        private const int EM_GETOLEINTERFACE = WM_USER + 60;
        public const int WM_USER = 0x0400;

        #endregion

        #region TOM OBJECT MODEL

        private ITextDocument _myITextDocument = null;
        private ITextDocument myITextDocument
        {
            get
            {
                if (_myITextDocument == null)
                    _myITextDocument = Create();

                return _myITextDocument;
            }
            set
            {
                if (_myITextDocument != null)
                    Marshal.ReleaseComObject(_myITextDocument);

                _myITextDocument = value;
            }
        }

        private ITextDocument Create()
        {
            IntPtr theRichEditOle = IntPtr.Zero;
            if (SendMessage(Handle, EM_GETOLEINTERFACE, IntPtr.Zero, out theRichEditOle) == 0)
            {
                throw new System.ComponentModel.Win32Exception();
            }

            try
            {
                ITextDocument theTextDoc = (ITextDocument)Marshal.GetTypedObjectForIUnknown(theRichEditOle, typeof(ITextDocument));
                return theTextDoc;
            }
            finally
            {
                Marshal.Release(theRichEditOle);
            }
        }

        private void FreezeDocument(ITextDocument doc)
        {
            doc.Freeze();
        }

        private void UnFreezeDocument(ITextDocument doc)
        {
            doc.Unfreeze();
        }

        private Boolean setForeColor(int start, int len, System.Drawing.Color backcolor)
        {
            Boolean ret = false;

            ITextRange range = myITextDocument.Range(start, start + len);

            FreezeDocument(myITextDocument);

            range.Font.ForeColor = System.Drawing.ColorTranslator.ToOle(backcolor);

            UnFreezeDocument(myITextDocument);

            return ret;
        }

        #endregion

        #region DELEGATE

        private delegate Boolean Updatecolor(int start, int len, System.Drawing.Color backcolor);

        #endregion

        #region KEYWORD C#

        private String[] Word = new String[] { 
            "abstract","as","base","bool","break","byte","case","catch","char","checked","class","const","continue","decimal",
            "default","delegate","do","double","else","enum","event","exdouble","exfloat","explicit","extern","false","finally","fixed",
            "float","for","foreach","get","goto","if","implicit","in","int","interface","internal","is","lock","long","namespace",
            "new","null","object","operator","out","override","private","protected","public","readonly","ref","return","sbyte","sealed",
            "set","short","sizeof","static","string","struct","switch","this","throw","true","try","typeof","uint","ulong","unchecked",
            "unsafe","ushort","using","virtual","void"
        };

        /// <summary>
        /// gerene un motif de regex
        /// </summary>
        /// <returns></returns>
        private string CompileKeywords()
        {
            string mKeywords = "";

            for (int i = 0; i < Word.Length; i++)
            {
                string strKeyword = Word[i];

                if (i == Word.Length - 1)
                    mKeywords += "\\b" + Word[i] + "\\b";
                else
                    mKeywords += "\\b" + Word[i] + "\\b|";
            }
            return mKeywords;
        }

        #endregion

        /// <summary>
        /// Mise a jour inter-Thread
        /// </summary>
        /// <param name="start">debut de mot</param>
        /// <param name="len">fin de mot</param>
        /// <param name="color">couleur désiré</param>
        private void UpdateContent(int start, int len, Color color)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new Updatecolor(setForeColor), new Object[] { start, len, color });
            }
            else
                setForeColor(start, len, color);
        }

        /// <summary>
        /// Color le text
        /// </summary>
        /// <param name="data">Text de la richtextbox</param>
        public void ColorSystaxe(object data)
        {
            String Text = data as String;
            Match regMatch;

            UpdateContent(0, Text.Length, Color.Black);

            /* color mot clé */
            Regex reg = new Regex(CompileKeywords(), RegexOptions.Singleline | RegexOptions.Compiled);
            for (regMatch = reg.Match(Text); regMatch.Success; regMatch = regMatch.NextMatch())
            {
                int nStart = regMatch.Index;
                int nLenght = regMatch.Length;
                UpdateContent(nStart, nLenght, Color.Blue);
            }

            /* color string avec ou sans @*/
            reg = new Regex("(@\"|\")[^\"]*(?:\\\\.[^\"]*)*\"", RegexOptions.Multiline | RegexOptions.Compiled);
            for (regMatch = reg.Match(Text); regMatch.Success; regMatch = regMatch.NextMatch())
            {
                int nStart = regMatch.Index;
                int nLenght = regMatch.Length;
                UpdateContent(nStart, nLenght, Color.Red);
            }

            /* color commentaire // */
            reg = new Regex("[^:]//[^\r\n]*", RegexOptions.Singleline | RegexOptions.Compiled);
            for (regMatch = reg.Match(Text); regMatch.Success; regMatch = regMatch.NextMatch())
            {

                int nStart = regMatch.Index;
                int nLenght = regMatch.Length;
                UpdateContent(nStart, nLenght, Color.Green);
            }

            /* color commentaire multiligne */
            reg = new Regex("/\\*([^*]|(\\*+([^*/])))*\\*+/", RegexOptions.Multiline | RegexOptions.Compiled);
            for (regMatch = reg.Match(Text); regMatch.Success; regMatch = regMatch.NextMatch())
            {
                int nStart = regMatch.Index;
                int nLenght = regMatch.Length;
                UpdateContent(nStart, nLenght, Color.Green);
            }
        }

        protected override void OnHandleCreated(EventArgs e)
        {
            base.OnHandleCreated(e);

            ColorSystaxe(Text);
        }

        protected override void OnTextChanged(EventArgs e)
        {
            base.OnTextChanged(e);

            /*

  • arrete le traitement si l'analise est dejas en cours
  • /
if (th != null && th.IsAlive) return; /*
  • lance l'analyse dans un thread
  • /
th = new Thread(new ParameterizedThreadStart(ColorSystaxe)); th.IsBackground = true; th.Start(Text); } } }

Conclusion :


je suis ouvert au remarque , essayé le !

A voir également

Ajouter un commentaire

Commentaires

Renfield
Messages postés
17286
Date d'inscription
mercredi 2 janvier 2002
Statut
Modérateur
Dernière intervention
23 décembre 2019
61
J'ai amélioré la chose, en supprimant le scintillement, et en relookant un peu le code (exit UpdateColor...)
Je n'avais pas besoin des Keywords, a vous de les remettre...

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Threading;
using tom;

namespace TextDefinitionWindow {
class RichTextBox : System.Windows.Forms.RichTextBox {
private struct ColorItem {
public Regex Regex;
public Color Forecolor;

public ColorItem(String vsPattern, RegexOptions veRegexOptions, Color veForeColor) {
Regex = new Regex(vsPattern, veRegexOptions | RegexOptions.Compiled);
Forecolor = veForeColor;
}
}

private Thread th = null;
private bool InternalChange = false;
private List<ColorItem> ColorItems = new List<ColorItem>();

public RichTextBox() {
}

#region WIN32
[DllImport("User32.dll")]
private static extern int SendMessage(IntPtr hWnd, int message, IntPtr wParam, out IntPtr lParam);

private const int EM_GETOLEINTERFACE = WM_USER + 60;
private const int WM_USER = 0x0400;
#endregion

#region TOM OBJECT MODEL
private ITextDocument _oTextDocument = null;
private ITextDocument TextDocument {
get {
if (_oTextDocument == null)
_oTextDocument = Create();
return _oTextDocument;
}
set {
if (_oTextDocument != null)
Marshal.ReleaseComObject(_oTextDocument);
_oTextDocument = value;
}
}

private ITextDocument Create() {
IntPtr oRichEditOle = IntPtr.Zero;
if (SendMessage(base.Handle, EM_GETOLEINTERFACE, IntPtr.Zero, out oRichEditOle) == 0)
throw new System.ComponentModel.Win32Exception();
try {
return (ITextDocument)Marshal.GetTypedObjectForIUnknown(oRichEditOle, typeof(ITextDocument));
}
finally {
Marshal.Release(oRichEditOle);
}
}

private delegate void SetForecolorDelegate(int vnStart, int vnLength, Color veForecolor);
private void SetForecolor(int vnStart, int vnLength, Color veForecolor) {
if (this.InvokeRequired)
this.Invoke(new SetForecolorDelegate(SetForecolor), new Object[] { vnStart, vnLength, veForecolor });
else {
ITextRange Range = TextDocument.Range(vnStart, vnStart + vnLength);
int ForeColor = ColorTranslator.ToOle(veForecolor);
// On n'appelle le coloriage que si nécessaire
if (Range.Font.ForeColor != ForeColor) {
InternalChange = true;
//TextDocument.Freeze();
Range.Font.ForeColor = ForeColor;
//TextDocument.Unfreeze();
InternalChange = false;
}
}
}
#endregion

public void SyntaxColor(object data) {
String Text = data as String;

// Permettra de mettre en noir le texte neutre.
List ColoredItems = new List();
ColoredItems.Add(0);
ColoredItems.Add(Text.Length);

foreach(ColorItem Item in ColorItems)
foreach (Match Match in Item.Regex.Matches(Text)) {
ColoredItems.Add(Match.Index);
ColoredItems.Add(Match.Index + Match.Length);
// On supprime le texte de l'item de la variable Texte.
Text = Text.Substring(0, Match.Index) + new String(' ', Match.Length) + Text.Substring(Match.Index + Match.Length);
SetForecolor(Match.Index, Match.Length, Item.Forecolor);
}

// On colorie en noir le texte restant
ColoredItems.Sort();
int[] TextIndexes = ColoredItems.ToArray();
for (int i = 0; i + 1 < TextIndexes.Length; i += 2)
SetForecolor(TextIndexes[i], TextIndexes[i + 1] - TextIndexes[i], Color.Black);
}

protected override void OnHandleCreated(EventArgs e) {
base.OnHandleCreated(e);

// J'ai plus ou moins laissé les Regexp, il faudrait les blinder un peu...
/* color commentaire // */
ColorItems.Add(new ColorItem("//[^\r\n]*", RegexOptions.Singleline, Color.Green));
/* color commentaire multiligne */
ColorItems.Add(new ColorItem("/\\*[\\s\\S]\\*/", RegexOptions.Multiline, Color.Green));
/* color string */
ColorItems.Add(new ColorItem(""[^\\\\]"", RegexOptions.Singleline, Color.Red));
SyntaxColor(base.Text);
}

protected override void OnTextChanged(EventArgs e) {
// Ne se déclenche pas pendant notre coloriage
if (!InternalChange) {
base.OnTextChanged(e);
if (th != null && th.IsAlive) {
// Plutot que de sortir (notre appel etant justifié)
// on annule le thread de coloriage en cours
th.Abort();
// On s'assure de l'efficacité de notre dernier appel
while (th.ThreadState != ThreadState.Stopped)
Thread.Sleep(1);
}
th = new Thread(new ParameterizedThreadStart(SyntaxColor));
th.IsBackground = true;
th.Start(Text);
}
}
}
}
TheManu
Messages postés
8
Date d'inscription
jeudi 26 juillet 2007
Statut
Membre
Dernière intervention
11 mai 2010

autant pour moi je ne l'avais pas vu. Merci
yohan49
Messages postés
380
Date d'inscription
samedi 22 janvier 2005
Statut
Membre
Dernière intervention
13 août 2011
7
salut il faut ajouter la reference COM tom
> yohan49
Messages postés
380
Date d'inscription
samedi 22 janvier 2005
Statut
Membre
Dernière intervention
13 août 2011

bonjour, où peut on trouver cette librairie tom ? merci

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.