Color specific words in RichtextBox - c#

How can I make, that when the user types specific words like 'while' or 'if' in a rich textbox, the words will color purple without any problems? I've tried diffrent codes, but none of them were usable. The codes were like below:
if (richTextBox.Text.Contains("while"))
{
richTextBox.Select(richTextBox.Text.IndexOf("while"), "while".Length);
richTextBox.SelectionColor = Color.Aqua;
}
Also, I want that when the user removes the word or removes a letter from the word, the word will color back to its default color. I'm making a program with a code editor in it.
I am using Visual c#.
Thank you.

Add an event to your rich box text changed,
private void Rchtxt_TextChanged(object sender, EventArgs e)
{
this.CheckKeyword("while", Color.Purple, 0);
this.CheckKeyword("if", Color.Green, 0);
}
private void CheckKeyword(string word, Color color, int startIndex)
{
if (this.Rchtxt.Text.Contains(word))
{
int index = -1;
int selectStart = this.Rchtxt.SelectionStart;
while ((index = this.Rchtxt.Text.IndexOf(word, (index + 1))) != -1)
{
this.Rchtxt.Select((index + startIndex), word.Length);
this.Rchtxt.SelectionColor = color;
this.Rchtxt.Select(selectStart, 0);
this.Rchtxt.SelectionColor = Color.Black;
}
}
}

This is something that you can do, I would recommend using a regular expression to find all matches of the word in case it occurs many times. Also keep in mind that the string find could be a list of strings out side of a for loop to consider multiple words but this should get you started.
//dont foget to use this at the top of the page
using System.Text.RegularExpressions;
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
string find = "while";
if (richTextBox1.Text.Contains(find))
{
var matchString = Regex.Escape(find);
foreach (Match match in Regex.Matches(richTextBox1.Text, matchString))
{
richTextBox1.Select(match.Index, find.Length);
richTextBox1.SelectionColor = Color.Aqua;
richTextBox1.Select(richTextBox1.TextLength, 0);
richTextBox1.SelectionColor = richTextBox1.ForeColor;
};
}
}

You can use richTextBox1_KeyDown event
private void richTextBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Space)
{
String abc = this.richTextBox1.Text.Split(' ').Last();
if (abc == "while")
{
int stIndex = 0;
stIndex = richTextBox1.Find(abc, stIndex, RichTextBoxFinds.MatchCase);
richTextBox1.Select(stIndex, abc.Length);
richTextBox1.SelectionColor = Color.Aqua;
richTextBox1.Select(richTextBox1.TextLength, 0);
richTextBox1.SelectionColor = richTextBox1.ForeColor;
}
}
}

If instead of a word you want to highlight a regular expression, you can use this:
private void ColorizePattern(string pattern, Color color)
{
int selectStart = this.textBoxSrc.SelectionStart;
foreach (Match match in Regex.Matches(textBoxSrc.Text, pattern))
{
textBoxSrc.Select(match.Index, match.Length);
textBoxSrc.SelectionColor = color;
textBoxSrc.Select(selectStart, 0);
textBoxSrc.SelectionColor = textBoxSrc.ForeColor;
};
}

Related

How to highlight a word or phrase with a color different from all the other selections in a RichTextBox text?

The main goal is to let an User identify a selection as the current, among all other selected words or phrases.
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
if (results.Count > 0)
{
richTextBox1.SelectionStart = results[(int)numericUpDown1.Value - 1];
richTextBox1.SelectionLength = textBox1.Text.Length;
richTextBox1.SelectionColor = Color.Red;
richTextBox1.ScrollToCaret();
}
}
In this case, in the screenshot, there are 3 results of the searched word: System. All the results colored in yellow.
If I change the NumericUpDown value to 2, it will color in red the second System word in the results and then when changing the NumericUpDown value to 3, it will color the last System result in red too.
My problem is that both 2 and 3 will be in colored in red: I want only the current selected word to be colored in red, all the other matches should use the default color.
A few suggestions that can help in building a class object that can handle selections of text.
This class should contain most (or all) the logic needed to search for keywords inside a given text, maintain a list of the matches found, their position and length and allows basic navigation of this list of matches, plus other configurations that can extend the functionality without much effort.
Here, the TextSearcher1 class constructor expects a RichTextBox control as one of the arguments, plus a Color used for the normal selection and a Color used to highlight the current match when the list of matches is navigated.
▶ The search functionality is handled by the Regex.Matches() method, which return a MatchCollection of Match objects, quite handy since each Match contains the position (Index property) of the match inside the text and its length (Length property).
▶ The navigation functionality is instead provided by a BindingSource object. Its DataSource property is set to the MatchCollection returned by Regex.Matches() and it's reset each time a new set of keywords is searched.
This class, when initialized, provides the MoveNext(), MovePrevious(), MoveLast() and MoveFirst() methods, plus a Position property, which identifies the Index of current object in the collection - a Match object, here.
▶ The CaseSensite property is used to perform case sensitive or insensitive searches. Added to show that it can be simple to expand the basic functionality with more features that build on the existing (for example, a culture sensitive/insensitive search).
To initialize the TextSearcher class, pass the instance of a RichTextBox control and two Color values to its contructor:
TextSearcher matchFinder = null;
public SomeForm()
{
InitializeComponent();
matchFinder = new TextSearcher(richTextBox1, Color.Yellow, Color.Red);
}
In the example, you can see four Controls:
The Previous (btnPrevious) and Next (btnNext) Buttons, used to navigate the list of matches.
A NumericUpDown (nudGotoMatch), used to jump to a specific matched keywork.
A TextBox (txtSearch), used to enter one or more keywords, separated by a pipe (the pipe char is used specify alternate matches in the Regex, it could be replaced with something else in the UI).
Since the TextSearcher class contains all the search and navigation logic, the code needed to activate the functionality of these controls in the front-end is minimal, just the standard UI requirements (such as setting e.SuppressKeyPress = true when the Enter key is pressed in a TextBox control).
private void txtSearch_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter) {
string keywords = (sender as Control).Text;
e.SuppressKeyPress = true;
if (!matchFinder.CurrentKeywords.Equals(keyword)) {
nudGotoMatch.Maximum = matchFinder.Search(keywords);
}
}
}
private void nudGotoMatch_ValueChanged(object sender, EventArgs e)
{
if (matchFinder.Matches.Count > 0) {
matchFinder.GotoMatch((int)nudGotoMatch.Value - 1);
}
}
private void btnPrevious_Click(object sender, EventArgs e)
{
matchFinder.PreviousMatch();
}
private void btnNext_Click(object sender, EventArgs e)
{
matchFinder.NextMatch();
}
This is how it works:
The TextSearcher class:
using System.Collections.Generic;
using System.Drawing;
using System.Text.RegularExpressions;
using System.Windows.Forms;
private class TextSearcher
{
private BindingSource m_bsMatches = null;
private RichTextBox m_Rtb = null;
public TextSearcher(RichTextBox rtb) : this(rtb, Color.Yellow, Color.Red) { }
public TextSearcher(RichTextBox rtb, Color selectionColor, Color currentColor)
{
m_Rtb = rtb;
SelectionColor = selectionColor;
CurrentColor = currentColor;
}
public string CurrentKeywords { get; private set; } = string.Empty;
public bool CaseSensitive { get; set; } = true;
public int CurrentIndex => m_bsMatches.Position;
public Match CurrentMatch => (Match)m_bsMatches.Current;
public MatchCollection Matches { get; private set; }
public Color SelectionColor { get; set; }
public Color CurrentColor { get; set; }
public void GotoMatch(int position)
{
SelectText(false);
m_bsMatches.Position = Math.Max(Math.Min(m_bsMatches.Count, position), 0);
SelectText(true);
}
public void NextMatch()
{
SelectText(false);
if (m_bsMatches != null && m_bsMatches.Position == m_bsMatches.Count - 1) {
m_bsMatches.MoveFirst();
}
else { m_bsMatches.MoveNext(); }
SelectText(true);
}
public void PreviousMatch()
{
SelectText(false);
if (m_bsMatches != null && m_bsMatches.Position > 0) {
m_bsMatches.MovePrevious();
}
else { m_bsMatches.MoveLast(); }
SelectText(true);
}
public int Search(string keywords)
{
if (CurrentKeywords.Equals(keywords)) return Matches.Count;
m_bsMatches?.Dispose();
CurrentKeywords = keywords;
var options = RegexOptions.Multiline |
(CaseSensitive ? RegexOptions.IgnoreCase : RegexOptions.None);
Matches = Regex.Matches(m_Rtb.Text, keywords, options);
if (Matches != null) {
m_Rtb.SelectAll();
m_Rtb.SelectionColor = m_Rtb.ForeColor;
m_Rtb.SelectionStart = 0;
m_bsMatches = new BindingSource(Matches, null);
SelectKeywords();
return Matches.Count;
}
return 0;
}
private void SelectKeywords()
{
foreach (Match m in Matches) {
SelectText(false);
NextMatch();
}
m_bsMatches.MoveFirst();
}
private void SelectText(bool current)
{
m_Rtb.Select(CurrentMatch.Index, CurrentMatch.Length);
m_Rtb.SelectionColor = current ? CurrentColor : SelectionColor;
}
}
1 - I know, great name! It took me a while to come up with it so, please, don't changed it :)

RichTextBox color specific line

How can I color a line in the RichTextBox which begins with a #, so like a comment in python. I have this code but it should color only the line where the # is in it. My code colors everything after one # is written:
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
string text = richTextBox1.Text;
if (richTextBox1.Lines.Contains("#") == true)
{
int firstcharindex = richTextBox1.GetFirstCharIndexOfCurrentLine();
int currentline = richTextBox1.GetLineFromCharIndex(firstcharindex);
richTextBox1.Select(firstcharindex, 10);
richTextBox1.SelectionColor = Color.Red;
richTextBox1.DeselectAll();
richTextBox1.Select(richTextBox1.Text.Length, 0);
}
}
You are missing the else condition, also do it for each line within TexBox like below
string text = richTextBox1.Text;
foreach (var line in richTextBox1.Lines)
{
if (line.Contains("#"))
{
int firstcharindex = richTextBox1.GetFirstCharIndexOfCurrentLine();
int currentline = richTextBox1.GetLineFromCharIndex(firstcharindex);
richTextBox1.Select(firstcharindex, 10);
richTextBox1.SelectionColor = Color.Red;
richTextBox1.DeselectAll();
richTextBox1.Select(richTextBox1.Text.Length, 0);
}
else
{
int firstcharindex = richTextBox1.GetFirstCharIndexOfCurrentLine();
int currentline = richTextBox1.GetLineFromCharIndex(firstcharindex);
richTextBox1.Select(firstcharindex, 10);
richTextBox1.SelectionColor = Color.Black;
richTextBox1.DeselectAll();
richTextBox1.Select(richTextBox1.Text.Length, 0);
}
}
You have to specify the richTextBox1.SelectionLength. You have to set this to your line length.
Also see: Selectively coloring text in RichTextBox

Changing character colour from input

I'm trying to change the colour of a character if the input from the text box matches the one in the rich text box.
char key = e.KeyChar;
for(int i = 0; i < rchtxtbox.Text.Length; i++)
{
char currentLetter = rchtxtbox.Text[i];
if (key == currentLetter)
{
rchtxtbox.SelectionStart = 0;
rchtxtbox.SelectionLength = 1;
rchtxtbox.SelectionColor = Color.White;
rchtxtbox.SelectionBackColor = Color.LightGreen;
}
}
It only highlights the current letter if it does matches. An example is if the word in the rich text box is "balloon" and the input first typed is "b", it matches and changes colour but if the next letter was added "ba" the function stops working and does not change colour. Other alternatives I have tried ended up changing the colours of all matched characters. I want to be able to colour it character by character if it matches, is there a way to do this easily?
Ok, here's how you can achieve this. I have used KeyUp event instead of keypress
private void textBox1_KeyUp(object sender, KeyEventArgs e) {
if (textBox1.TextLength == 0) { return; }
int index;
index = textBox1.TextLength - 1;
char key = textBox1.Text[index];
if (rchtxtbox.TextLength > index && rchtxtbox.Text[index] == key) {
if (rchtxtbox.Text[index] == key) {
rchtxtbox.SelectionStart = index;
rchtxtbox.SelectionLength = 1;
rchtxtbox.SelectionColor = Color.White;
rchtxtbox.SelectionBackColor = Color.LightGreen;
}
}
}
Make sure you replace textBox1 above with the name of your textbox
If I am understanding your questions correctly, the issue is just that you are only ever selecting the first character for highlight.
You should be setting SelectionStart to i, so it selects and highlights the character you are comparing against:
rchtxtbox.SelectionStart = i;
Edit:
After thinking about what you're trying to do, I think you have a rich text box with text in it. You also have a text box that the user is typing into. As the user types into the text box, you want to highlight that text in the rich text box. Correct?
Here is a simple example, although this doesn't account for multiple occurrences of the text being found.
private void textBox1_TextChanged(object sender, EventArgs e)
{
int idx = richTextBox1.Text.IndexOf(textBox1.Text);
if (idx > -1)
{
richTextBox1.SelectionStart = idx;
richTextBox1.SelectionLength = textBox1.Text.Length;
richTextBox1.SelectionColor = Color.White;
richTextBox1.SelectionBackColor = Color.LightGreen;
}
}

RichTextBox text color

I created RichTextBox and I add this code:
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
//( )
int selectionStart = richTextBox1.SelectionStart;
string helpText = richTextBox1.Text;
int closerPos;
for (int i = 0; i < helpText.Length; i++)
{
if (helpText[i] == '(')
{
selectionStart = richTextBox1.SelectionStart;
closerPos = helpText.Substring(i).IndexOf(')') + i;
helpText = helpText.Substring(i + 1, closerPos - i - 1);
richTextBox1.Text = richTextBox1.Text.Remove(i + 1, closerPos - i - 1);
richTextBox1.Select(i + 1, 0);
richTextBox1.SelectionColor = Color.Red;
richTextBox1.SelectedText = helpText;
richTextBox1.SelectionColor = Color.Black;
helpText = richTextBox1.Text;
richTextBox1.SelectionStart = selectionStart;
}
}
}
This code should color the text between the ( ).
For example:
"Hi (need to be colored) text (sdadsasd) "
the text between the ( ) need to be colored in red. but only the last text is colored. How can I fix it?
You're only getting the first paranthesis with that if condition.
Try splitting the text like helpText.Split('(');
Then iterate over it and do your logic.
I think you can accomplish this without moving byte by byte. You can try to do it using the IndexOf method.
This is something I was thinking of:
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
string rbText = richTextBox1.Text;
int position = 0;
int startBrace = rbText.IndexOf('(', position) + 1;
while (startBrace != -1)
{
position = rbText.IndexOf(')', startBrace);
if (position != -1)
{
richTextBox1.Select(startBrace, position - startBrace);
richTextBox1.SelectionColor = Color.Red;
startBrace = rbText.IndexOf('(', position) + 1;
}
else
break;
}
}
Keep in mind that I haven't fully test this code.
I already see a potential issue, helpText is being used as an array when it is only a single-variable string. Try breaking the entirety of helpText down into a char array, then iterating through that to find your brackets.

Change font color as the user types in RichTextBox

I want to create a simple text editor but supports multicolor font like a "Compiler"
Assume my program keywords are: "dog","cow","cat","bird"
I have a RichTextBox that implements TextChanged event.
now, My problem is I don't know how to change the font color when a keyword is encountered.
Example String: A Big Dog and a Cat
Dog will be color RED while cat will be color GREEN.
I'm not sure how effecient this will be when you have massive amounts of text, but it works fairly well to the extent that I have tested it.
private void CheckKeyword(string word, Color color, int startIndex)
{
if (this.richTextBox1.Text.Contains(word))
{
int index = -1;
int selectStart = this.richTextBox1.SelectionStart;
while ((index = this.richTextBox1.Text.IndexOf(word, (index + 1))) != -1)
{
this.richTextBox1.Select((index + startIndex), word.Length);
this.richTextBox1.SelectionColor = color;
this.richTextBox1.Select(selectStart, 0);
this.richTextBox1.SelectionColor = Color.Black;
}
}
}
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
this.CheckKeyword("dog", Color.Red, 0);
this.CheckKeyword("cat", Color.Green, 0);
}

Categories