I have a RichTextBox with -by example- this text:
"This is my Text"
Now I want to "search" the RichTextBox for a Text (String), by example:
"Text"
Now "Text" should be selected/highlighted (for each one) in the RichTextBox..
There is something like:
myRichTextBox.Select();
but here I have to set a StartPosition and so on, but I want to search for String!
How could I do this? (Searched stackoverflow, didn't find something similiar..)
int start = 0;
int indexOfSearchText = 0;
private void btnFind_Click(object sender, EventArgs e)
{
int startindex = 0;
if(txtSearch.Text.Length > 0)
startindex = FindMyText(txtSearch.Text.Trim(), start, rtb.Text.Length);
// If string was found in the RichTextBox, highlight it
if (startindex >= 0)
{
// Set the highlight color as red
rtb.SelectionColor = Color.Red;
// Find the end index. End Index = number of characters in textbox
int endindex = txtSearch.Text.Length;
// Highlight the search string
rtb.Select(startindex, endindex);
// mark the start position after the position of
// last search string
start = startindex + endindex;
}
}
public int FindMyText(string txtToSearch, int searchStart, int searchEnd)
{
// Unselect the previously searched string
if (searchStart > 0 && searchEnd > 0 && indexOfSearchText >= 0)
{
rtb.Undo();
}
// Set the return value to -1 by default.
int retVal = -1;
// A valid starting index should be specified.
// if indexOfSearchText = -1, the end of search
if (searchStart >= 0 && indexOfSearchText >=0)
{
// A valid ending index
if (searchEnd > searchStart || searchEnd == -1)
{
// Find the position of search string in RichTextBox
indexOfSearchText = rtb.Find(txtToSearch, searchStart, searchEnd, RichTextBoxFinds.None);
// Determine whether the text was found in richTextBox1.
if (indexOfSearchText != -1)
{
// Return the index to the specified search text.
retVal = indexOfSearchText;
}
}
}
return retVal;
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
start = 0;
indexOfSearchText = 0;
}
CheckOut this article if you dont understand this code...
http://www.dotnetcurry.com/ShowArticle.aspx?ID=146
You can only have one selection in a text box. What you want is to highlight the found text.
You could achieve it like this:
Find the positions of the text you want to highlight using repeated calls to myRichTextBox.Text.IndexOf with the last found index + 1 as the start position.
Highlight the found texts using the default RichTextBox capabilities.
You can use the Find method to find the startindex of your searched text:
int indexToText = myRichTextBox.Find(searchText);
You can then use this index and the Select method to select the text:
int endIndex = searchText.Length;
myRichTextBox.Select(indexToText , endIndex);
private void Txt_Search_Box_TT_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
FOFO:
int start =
RtfAll_Messages.Find(Txt_Search_Box_TT.Text, RtfAll_Messages.SelectionStart + 1,
RichTextBoxFinds.None);
if (start >= 0)
RtfAll_Messages.Select(start, Txt_Search_Box_TT.Text.Length);
else
{
start = 0;
RtfAll_Messages.SelectionStart = 0;
RtfAll_Messages.SelectionLength = 0;
}
}
}
Related
richTextBox1 contains text
I click on a word and Console displays that word for me and it highlights/selects the word i clicked on.
To do this, I keep the index of the character I clicked on then go left and right until I hit a space, -1, or end of file. Now I have the indexes of the beginning and end of the word. The last two lines are supposed to select the word between those two indexes.
However, what happens is that sometimes it highlights the word I want and sometimes it highlights all the words to the right of the character I clicked on.
"omar hello where are you going"
If I click on h in hello, it highlights hello where instead of highlighting hello
If I click on o in going, it will highlight going only as it should
If I click on o in you, it will highlight you going
I used console to check the start and end indexes of the word and they're always right yet for some reason, other words are selected in addition to the word i clicked on
private void richTextBox1_Click(object sender, EventArgs e)
{
int length = richTextBox1.Text.Length;
int rightPart = richTextBox1.SelectionStart;
int leftPart = richTextBox1.SelectionStart - 1;
string rightText = "";
string leftText = "";
while (rightPart != length)
{
if (richTextBox1.Text[rightPart].ToString().CompareTo(" ") != 0)
{
rightText += richTextBox1.Text[rightPart];
rightPart++;
}
else
{
break;
}
}
while (leftPart != -1)
{
if (richTextBox1.Text[leftPart].ToString().CompareTo(" ") != 0)
{
leftText = richTextBox1.Text[leftPart] + leftText;
leftPart--;
}
else
{
break;
}
}
leftPart++;
Console.WriteLine("\nSelected word is " + leftText + rightText + "\n");
richTextBox1.SelectionStart = leftPart;
richTextBox1.SelectionLength = rightPart;
}
The problem appears to be that you are setting the SelectionLength equal to rightPart. Remember this property represents the length of the selection, not the last index of the selection.
Instead, try changing your code to calculate the length by getting the difference between leftPart and rightPart:
richTextBox1.SelectionLength = rightPart - leftPart;
For what it's worth, your code can be shortened a little:
private void richTextBox1_Click(object sender, EventArgs e)
{
if (richTextBox1.TextLength == 0) return;
int rightPart = richTextBox1.SelectionStart;
int leftPart = richTextBox1.SelectionStart - 1;
while (rightPart < richTextBox1.TextLength && richTextBox1.Text[rightPart] != ' ')
{
rightPart++;
}
while (leftPart > -1 && richTextBox1.Text[leftPart] != ' ')
{
leftPart--;
}
leftPart++;
Console.WriteLine($"\nSelected word is " +
richTextBox1.Text.Substring(leftPart, rightPart - leftPart) + "\n");
richTextBox1.SelectionStart = leftPart;
richTextBox1.SelectionLength = rightPart - leftPart;
}
Or even a little more, using IndexOf and LastIndexOf instead of loops to find the spaces:
private void richTextBox1_Click(object sender, EventArgs e)
{
if (richTextBox1.TextLength == 0) return;
// Find the space before this word and after this word
var selStart = Math.Min(richTextBox1.SelectionStart, richTextBox1.TextLength - 1);
var firstSpace = richTextBox1.Text.LastIndexOf(' ', selStart);
var lastSpace = richTextBox1.Text.IndexOf(' ', selStart);
var start = firstSpace + 1;
var length = (lastSpace < 0 ? richTextBox1.TextLength : lastSpace) - start;
Console.WriteLine($"\nSelected word is {richTextBox1.Text.Substring(start, length)} \n");
richTextBox1.SelectionStart = start;
richTextBox1.SelectionLength = length;
}
In my RichtextBox, if I have written as below.
This is my pen,
his pen is beautiful.
Now I search word "is" then
output would be as below.
All "is" should be highlighted.
What about:
static class Utility {
public static void HighlightText(this RichTextBox myRtb, string word, Color color) {
if (word == string.Empty)
return;
int s_start = myRtb.SelectionStart, startIndex = 0, index;
while((index = myRtb.Text.IndexOf(word, startIndex)) != -1) {
myRtb.Select(index, word.Length);
myRtb.SelectionColor = color;
startIndex = index + word.Length;
}
myRtb.SelectionStart = s_start;
myRtb.SelectionLength = 0;
myRtb.SelectionColor = Color.Black;
}
}
Looks like this would do it.
http://www.dotnetcurry.com/ShowArticle.aspx?ID=146
int start = 0;
int indexOfSearchText = 0;
private void btnFind_Click(object sender, EventArgs e)
{
int startindex = 0;
if(txtSearch.Text.Length > 0)
startindex = FindMyText(txtSearch.Text.Trim(), start, rtb.Text.Length);
// If string was found in the RichTextBox, highlight it
if (startindex >= 0)
{
// Set the highlight color as red
rtb.SelectionColor = Color.Red;
// Find the end index. End Index = number of characters in textbox
int endindex = txtSearch.Text.Length;
// Highlight the search string
rtb.Select(startindex, endindex);
// mark the start position after the position of
// last search string
start = startindex + endindex;
}
}
public int FindMyText(string txtToSearch, int searchStart, int searchEnd)
{
// Unselect the previously searched string
if (searchStart > 0 && searchEnd > 0 && indexOfSearchText >= 0)
{
rtb.Undo();
}
// Set the return value to -1 by default.
int retVal = -1;
// A valid starting index should be specified.
// if indexOfSearchText = -1, the end of search
if (searchStart >= 0 && indexOfSearchText >=0)
{
// A valid ending index
if (searchEnd > searchStart || searchEnd == -1)
{
// Find the position of search string in RichTextBox
indexOfSearchText = rtb.Find(txtToSearch, searchStart, searchEnd, RichTextBoxFinds.None);
// Determine whether the text was found in richTextBox1.
if (indexOfSearchText != -1)
{
// Return the index to the specified search text.
retVal = indexOfSearchText;
}
}
}
return retVal;
}
// Reset the richtextbox when user changes the search string
private void textBox1_TextChanged(object sender, EventArgs e)
{
start = 0;
indexOfSearchText = 0;
}
This will show all the searched criteria at the same time.
Using: 1 Textbox (to enter the text to search for) and 1 Button (to Run the Search).
Enter your search criteria inside the textbox and press search button.
// On Search Button Click: RichTextBox ("rtb") will display all the words inside the document
private void btn_Search_Click(object sender, EventArgs e)
{
try
{
if (rtb.Text != string.Empty)
{// if the ritchtextbox is not empty; highlight the search criteria
int index = 0;
String temp = rtb.Text;
rtb.Text = "";
rtb.Text = temp;
while (index < rtb.Text.LastIndexOf(txt_Search.Text))
{
rtb.Find(txt_Search.Text, index, rtb.TextLength, RichTextBoxFinds.None);
rtb.SelectionBackColor = Color.Yellow;
index = rtb.Text.IndexOf(txt_Search.Text, index) + 1;
rtb.Select();
}
}
}
catch (Exception ex) { MessageBox.Show(ex.Message, "Error"); }
}
}
}
If you only want to match the whole word you can use this, note that this ignores case and also the |s\b means that plurals get highlighted e.g. Cat matches cats but not caterpiller :
public static void HighlightText(RichTextBox myRtb, string word, Color color)
{
if (word == string.Empty)
return;
var reg = new Regex(#"\b" + word + #"(\b|s\b)",RegexOptions.IgnoreCase);
foreach (Match match in reg.Matches(myRtb.Text))
{
myRtb.Select(match.Index, match.Length);
myRtb.SelectionColor = color;
}
myRtb.SelectionLength = 0;
myRtb.SelectionColor = Color.Black;
}
private void button3_Click(object sender, EventArgs e)
{
if (textBox1.Text != "")
{
for (int i = 0; i < richTextBox1.TextLength; i++)
{
richTextBox1.Find(textBox1.Text, i, RichTextBoxFinds.None);
richTextBox1.SelectionBackColor = Color.Red;
}
}
else
{
for (int i = 0; i < richTextBox1.TextLength; i++)
{
richTextBox1.SelectAll();
richTextBox1.SelectionBackColor = Color.White;
}
}
}[lets make it!][1]
I would do it like that because all the other answers highlight the text, but doesnt change it back after you searched again.
Use the RichText Find Method to find the starting index for the searching word.
public int FindMyText(string searchText, int searchStart, int searchEnd)
{
int returnValue = -1;
if (searchText.Length > 0 && searchStart >= 0)
{
if (searchEnd > searchStart || searchEnd == -1)
{
int indexToText = richTextBox1.Find(searchText, searchStart, searchEnd, RichTextBoxFinds.MatchCase);
if (indexToText >= 0)
{
returnValue = indexToText;
}
}
}
return returnValue;
}
Use a Button or TextChangeListener and Search for your word.
private void button1_Click(object sender, EventArgs e)
{
// Select the first char in your Richtextbox
richTextBox1.SelectionStart = 0;
richTextBox1.SelectionLength = richTextBox1.TextLength;
// Select until the end
richTextBox1.SelectionColor = Color.Black;
// Make the Text Color black
//Use an Inputfield to add the searching word
var word = txtSearch.Text;
//verify the minimum length otherwise it may freeze if you dont have text inside
if (word.Length > 3)
{
int s_start = richTextBox1.SelectionStart, startIndex = 0, index;
while ((index = FindMyText(word, startIndex, richTextBox1.TextLength)) != -1)
{
// goes through all possible found words and color them blue (starting index to end)
richTextBox1.Select(index, word.Length);
richTextBox1.SelectionColor = Color.Blue;
startIndex = index + word.Length;
}
// Color everything between in color black to highlight only found words
richTextBox1.SelectionStart = startIndex;
richTextBox1.SelectionLength = 0;
richTextBox1.SelectionColor = Color.Black;
}
}
I would highly recommend to set a minimum word length to avoid freezing and high memory allocation.
I have a richTextBox that I use so the user can see the XML file they have and let them edit it. I have some code that changes keywords colours into a colour I specify. This is the method that I use:
private void CheckKeyword(string word, Color color, int startIndex)
{
if (this.richTextBox.Text.Contains(word))
{
int index = -1;
int selectStart = this.richTextBox.SelectionStart;
while ((index = this.richTextBox.Text.IndexOf(word, (index + 1))) != -1)
{
this.richTextBox.Select((index + startIndex), word.Length);
this.richTextBox.SelectionColor = color;
this.richTextBox.Select(selectStart, 0);
this.richTextBox.SelectionColor = Color.Black;
}
}
}
The problem is that when I click
near a coloured string, I start typing in that specific colour.
I know why its happening, but don't know how to fix it.
You will have to determine whether or not your cursor is "inside" a keyword area or not at KeyDown, so wire up the KeyDown event and try using this code. I'm sure there's a more efficient way to determine whether or not your cursor is inside a bracketed keyword, but this seems to get the job done:
void rtb_KeyDown(object sender, KeyEventArgs e) {
int openIndex = rtb.Text.Substring(0, rtb.SelectionStart).LastIndexOf('<');
if (openIndex > -1) {
int endIndex = rtb.Text.IndexOf('>', openIndex);
if (endIndex > -1) {
if (endIndex + 1 <= this.rtb.SelectionStart) {
rtb.SelectionColor = Color.Black;
} else {
string keyWord = rtb.Text.Substring(openIndex + 1, endIndex - openIndex - 1);
if (keyWord.IndexOfAny(new char[] { '<', '>' }) == -1) {
this.rtb.SelectionColor = Color.Blue;
} else {
this.rtb.SelectionColor = Color.Black;
}
}
} else {
this.rtb.SelectionColor = Color.Black;
}
} else {
this.rtb.SelectionColor = Color.Black;
}
}
I've got a find next and previous function and edited it so that when the user selects text in a textbox and clicks on either Find Next or Find Previous button, the find feature will start it's index from the selected character and go through each search result (initially the feature wasn't there). To get the starting index of the selected text I created a function:
private int GetIntialCharPos(string Text)
{
int row = Variables._TextBox.GetLineIndexFromCharacterIndex(Variables._TextBox.CaretIndex);
int col = Variables._TextBox.CaretIndex - Variables._TextBox.GetCharacterIndexFromLineIndex(row);
return col;
}
The function which does the Find Next and Previous goes as follows:
private List<int> _matches;
private string _textToFind;
private bool _matchCase;
private int _matchIndex;
private void MoveToNextMatch(string textToFind, bool matchCase, bool forward)
{
if (_matches == null || _textToFind != textToFind || _matchCase != matchCase)
{
int startIndex = 0, matchIndex;
StringComparison mode = matchCase ? StringComparison.CurrentCulture : StringComparison.CurrentCultureIgnoreCase;
_matches = new List<int>();
while (startIndex < Variables._TextBox.Text.Length && (matchIndex = Variables._TextBox.Text.IndexOf(textToFind, startIndex, mode)) >= 0)
{
_matches.Add(matchIndex);
startIndex = matchIndex + textToFind.Length;
}
_textToFind = textToFind;
_matchCase = matchCase;
_matchIndex = forward ? _matches.IndexOf(GetIntialCharPos(textToFind)) : _matches.IndexOf(GetIntialCharPos(textToFind)) - 1;
}
else
{
_matchIndex += forward ? 1 : -1;
if (_matchIndex < 0)
{
_matchIndex = _matches.Count - 1;
}
else if (_matchIndex >= _matches.Count)
{
_matchIndex = 0;
}
}
if (_matches.Count > 0)
{
Variables._TextBox.SelectionStart = _matches[_matchIndex];
Variables._TextBox.SelectionLength = textToFind.Length;
Variables._TextBox.Focus();
}
}
My issue is that once the user has selected the text he needs to search, and goes through the find next and previous buttons, and then he decides to select the text from a different index, rather than continuing the search from the selected index, it will maintain the default initial order which it goes by rather than starting from the selected index and going through each result from that. I created a small gif video here so you can take a better look at this problem.
How do I preserve the selected word index so every time the user selects from a different index it can start the search from the index in which the user selected rather than always starting from the start.
private int _matchIndex;
That's your problem variable. It retains the last match index but you don't know when the user changes it by himself. The TextBox class does not have a SelectionChanged event to tell you about it so there is no simple way to reset the variable.
Simply use a RichTextBox instead, it does have that event.
But it is much easier, this bug occurred because you added state unnecessarily by splitting of the searching operation into a separate class. State is in general a bad thing, it is a bug generator. You can trivially make the entire operation stateless by using the TextBox object directly:
private static void MoveToNextMatch(TextBoxBase box, bool forward) {
var needle = box.SelectedText;
var haystack = box.Text;
int index = box.SelectionStart;
if (forward) {
index = haystack.IndexOf(needle, index + 1);
if (index < 0) index = haystack.IndexOf(needle, 0);
}
else {
if (index == 0) index = -1;
else index = haystack.LastIndexOf(needle, index - 1);
if (index < 0) index = haystack.LastIndexOf(needle, haystack.Length - 1);
}
if (index >= 0) {
box.SelectionStart = index;
box.SelectionLength = needle.Length;
}
box.Focus();
}
Use the Last/IndexOf() method that takes a StringComparison to implement the matchCase argument.
There is a richTextBox on a windows form in C#. I'm looking for a special string by find method.
For example I'm looking for 'cat' string in the text. As you know there could be a lot of string depends on cat like: cat or cats or cat's or Cat or CAT or cat. or cat, or cat: or cat\n or even something like category or catalyst or Catia and other types. How can I look for just cat as an animal like cat, or cat: or cat. or cat or cat's or cats and etc. Is there any character that I can use instead? something like ' cat?' or ' cat*' to look for all of characters.
This is the method I'm using:
private void treeView1_AfterCheck(object sender, TreeViewEventArgs e)
{
if (e.Node.Checked)
{
CheckedNodes.Add(e.Node);
}
else
{
CheckedNodes.Remove(e.Node);
}
richTextBox1.SelectAll();
richTextBox1.SelectionBackColor = Color.White;
richTextBox1.DeselectAll();
for (int counter = 0; counter < CheckedNodes.Count; counter++)
{
int location = 0;
while (location != -1)
{
location = FindMyText(" " + CheckedNodes[counter].Text + "", location + 1, richTextBox1.TextLength);
if (location != -1)
{
FindMyText(CheckedNodes[counter].Text, location + 1, richTextBox1.TextLength);
richTextBox1.SelectionBackColor = CheckedNodes[counter].ForeColor;
}
}
}
richTextBox1.DeselectAll();
}
public int FindMyText(string searchText, int searchStart, int searchEnd)
{
// Initialize the return value to false by default.
int returnValue = -1;
// Ensure that a search string and a valid starting point are specified.
if (searchText.Length > 0 && searchStart >= 0)
{
// Ensure that a valid ending value is provided.
if (searchEnd > searchStart || searchEnd == -1)
{
// Obtain the location of the search string in richTextBox1.
int indexToText = richTextBox1.Find(searchText, searchStart, searchEnd, RichTextBoxFinds.MatchCase);
// Determine whether the text was found in richTextBox1.
if (indexToText >= 0)
{
// Return the index to the specified search text.
returnValue = indexToText;
}
}
}
return returnValue;
}
Here you can find an Enhanced Rich text box control, the only problem that its in VB.net,
http://www.codeproject.com/Articles/32793/RichTextBox-Control-with-Find-functionality
but it solves your problem.