Issues changing color in richtextbox - c#

I'm trying to iterate through some pre-typed text in a Richtextbox and change the color of specific words/lines to a color depending on their prefix, thus far the different prefix's are [b], [f], and [e]. In this example I only use [b]. I've tried using while/foreach loops but they don't seem to iterate through the text. Below is the closest I've come to making it work but it only works on the first line of text. Any chance someone can point me in the correct direction?
private void AboutBox_Load(object sender, EventArgs e)
{
textBox1.Select(0, 0);
using (StringReader reader = new StringReader(richTextBox1.Text))
{
string line = string.Empty;
do
{
line = reader.ReadLine();
if ((line != null && line.Contains("[b]")))
{
richTextBox1.Select(richTextBox1.Text.IndexOf("[b]"), "[b]".Length);
richTextBox1.SelectionColor = Color.Green;
}
} while (line != null);
}
}

Instead of copying the text to a string, you can work directly with the RichTextBox via its Find() method:
void AboutBox_Load(object sender, EventArgs e)
{
this.ColorPrefix(richTextBox1, "[b]", Color.Green);
this.ColorPrefix(richTextBox1, "[f]", Color.Red); // change the color!
this.ColorPrefix(richTextBox1, "[e]", Color.Yellow); // change the color!
}
private void ColorPrefix(RichTextBox rtb, string prefix, Color color)
{
int position = 0, index = 0;
while ((index = rtb.Find(prefix, position, RichTextBoxFinds.None)) >= 0)
{
rtb.Select(index, prefix.Length);
rtb.SelectionColor = color;
position = index + 1;
}
rtb.Select(rtb.TextLength, 0);
}

This line will always select the same item:
richTextBox1.Select(richTextBox1.Text.IndexOf("[b]"), "[b]".Length);
So I would suggest something like this:
private void AboutBox_Load(object sender, EventArgs e)
{
string text = richTextBox1.Text;
int position = 0, index = 0;
while ((index = text.IndexOf("[b]", position)) >= 0)
{
richTextBox1.Select(index, 3);
richTextBox1.SelectionColor = Color.Green;
position = index + 1;
}
}

If you like to highlight syntax, I suggest using the FastColoredTextBox control:

Related

how to change color of equal signs in richtextbox c#

I want to change color of equal sign as it happens in notepad++ while the user writes the text . My code is working but the cursor is stuck on one place and user cannot write anything in between the text it only allows to write it in the end , also does not detect when newline is present after =. How to do it ?
private void richTextBox1_KeyPress(object sender, KeyPressEventArgs e)
{
equal();
}
public void equal()
{
start = richTextBox1.Text.Length - 1;
length = 1;
richTextBox1.SelectionStart = start;
richTextBox1.SelectionLength = length;
string settext = richTextBox1.SelectedText;
if ( settext ==Convert.ToString('='))
{
richTextBox1.SelectionColor = Color.Purple;
}
}
Add event to your richtext box for text changed:
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
this.ChangeColor("=", Color.Purple);
}
private void ChangeColor(string word, Color color)
{
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), word.Length);
this.richTextBox1.SelectionColor = color;
this.richTextBox1.Select(selectStart, 0);
this.richTextBox1.SelectionColor = Color.Black;
}
}
}
Please use the richTextBox_TextChanged event for changing the color. I have met this problem once in my application.

Creating a game of Checkers

I am creating this in regards to an issue I just ran in with. I am trying to create a primitive game of checkers using only buttons and so far I am just testing how to get the program to recognize selecting a button and moving the piece.
My Code:
private void Checkers_Load(object sender, EventArgs e)
{
}
string selectedChecker = "";
string currentButton = "";
int blankSpace = 0;
int[] Board = new int[64];
private void gameBoard()
{
foreach(var control in Controls)
{
var button = control as Button;
if(button != null)
{
if(button.Name == currentButton)
{
button.Image = System.Drawing.Image.FromFile("Red Checker.png");
}
else
{
MessageBox.Show("Dead.");
}
}
else
{
MessageBox.Show("Dead.");
}
}
}
private void attemptMove()
{
string substringChecker = null;
substringChecker = selectedChecker.Substring(0,2);
int selectedCheckerNumber = Convert.ToInt32(substringChecker);
string substringButton = null;
substringButton = currentButton.Substring(0,2);
int currentButtonNumber = Convert.ToInt32(substringButton);
if((selectedCheckerNumber + 3 == currentButtonNumber) || (selectedCheckerNumber + 4 == currentButtonNumber))
{
Board[currentButtonNumber] = Board[selectedCheckerNumber];
Board[selectedCheckerNumber] = blankSpace;
gameBoard();
}
}
private void newGameToolStripMenuItem_Click(object sender, EventArgs e)
{
int w = pictureBox1.Size.Width;
int h = pictureBox1.Size.Height;
int count = 8;
Bitmap b = new Bitmap(w, h, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
w /= count;
h /= count;
Graphics g = Graphics.FromImage(b);
for (int i = 0; i < count; i++)
{
for (int j = 0; j < count; j++)
{
Color c = (i + j) % 2 == 0 ? Color.Red : Color.Black;
Brush br = new SolidBrush(c);
g.FillRectangle(br, i * w, j * h, w, h);
br.Dispose();
}
}
g.Dispose();
pictureBox1.Image = b;
pictureBox1.Refresh();
}
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
//Close form
this.Close();
}
private void howToPlayToolStripMenuItem_Click(object sender, EventArgs e)
{
//MessageBox.Show("How to play a game of Checkers: Step 1 - Don't play.");
}
private void informationToolStripMenuItem_Click(object sender, EventArgs e)
{
}
private void checkerSpace18_Click(object sender, EventArgs e)
{
}
private void checkerSpace17_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
string buttonClicked = btn.Name;
if (selectedChecker == "")
{
selectedChecker = buttonClicked;
}
else
{
currentButton = buttonClicked;
attemptMove();
}
}
}
My question goes with regards to my attemptMove() method. I run into a runtime error:
"An unhandled exception of type 'System.FormatException' occurred in mscorlib.dll. Additional information: Input string was not in a correct format."
It seems to occur whenever I go to move the piece to the other cell adjacent to the piece after moving it once. It may be because my program is not updating the pictures of the buttons when the buttons switch, but I wanted to see if any guidance could be shed upon this issue.
You are setting the "selectedChecker" to the clicked button .Name property. Then you are using substring(0,2) to get the first 2 characters and try to convert that to an integer.
Since a Name property can't start with numbers, you are attempting to convert some random text to an integer property.
A better approach would be to use the Tag property to hold information about the number, this can be any value. You can then use the int.Parse to parse the Tag value of the button.
What is your naming convention for the buttons? Seems like you're trying to get a number from the name, but the conversion is failing.
If the button names are button00 through button63, then you should be able to get the number using Substring, starting at Name.Length - 2. Note that you must have all button names use a two digit number at the end (00, 01, 02, etc).
For example:
// Get the last two characters of the button name
string substringChecker = selectedChecker.Substring(selectedChecker.Length - 2);
// Convert the characters to an integer
int selectedCheckerNumber = Convert.ToInt32(substringChecker);

Creating a custom Multi-Line Listbox

In the creation of some apps, a list-box with multiple lined content is preferred. Since listboxes have no such function, the creation of a custom control is needed. For this case, I'm working on a compiler app that the user can load an import and export C# prefab into the program to manipulate data. To see this compiler in action, you can check out my previous post here. For this instance, I want a debug log of any errors to be outputted into the listbox. Since some errors contain multiple lines, some of which are rather long, I read up and generated a Listbox of Textbox items.
The most current copy of this can be found on pastebin.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace DataStripper
{
public partial class MultiLineListView : System.Windows.Forms.ListBox
{
public MultiLineListView()
{
//InitializeComponent();
this.DrawMode = DrawMode.OwnerDrawVariable;
this.ScrollAlwaysVisible = true;
tbox.Hide();
tbox.mllb = this;
Controls.Add(tbox);
}
protected override void OnMeasureItem(MeasureItemEventArgs e)
{
if (Site != null)
return;
if (e.Index > -1)
{
string s = Items[e.Index].ToString();
float best = 0;
foreach (string line in s.Split(new string[] { Environment.NewLine }, StringSplitOptions.None))
{
float chk = e.Graphics.MeasureString(line, Font, Width).Width;
if (chk > best)
best = chk;
}
SizeF sf = e.Graphics.MeasureString(s, Font, Width);
int htex = 1;//(e.Index == 0) ? 15 : 10;
e.ItemHeight = (int)(sf.Height*Items.Count) + htex;
e.ItemWidth = (int)best;
/*NTextBox i = (NTextBox)Items[e.Index];
e.ItemHeight = i.Height;
e.ItemWidth = i.Width;*/
}
}
protected override void OnDrawItem(DrawItemEventArgs e)
{
if (Site != null)
return;
if (e.Index > -1)
{
string s = Items[e.Index].ToString();
if ((e.State & DrawItemState.Focus) == 0)
{
e.Graphics.FillRectangle(new SolidBrush(SystemColors.Window), e.Bounds);
e.Graphics.DrawString(s, Font, new SolidBrush(SystemColors.WindowText),
e.Bounds);
e.Graphics.DrawRectangle(new Pen(SystemColors.Highlight), e.Bounds);
}
else
{
e.Graphics.FillRectangle(new SolidBrush(SystemColors.Highlight), e.Bounds);
e.Graphics.DrawString(s, Font, new SolidBrush(SystemColors.HighlightText),
e.Bounds);
}
}
}
protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs e)
{
int index = IndexFromPoint(e.X, e.Y);
if (index != ListBox.NoMatches &&
index != 65535)
{
/*if (e.Button == MouseButtons.Right)
{
SelectedIndex = index;
Focus();
//tbox.index = index;
}*/
/*if (e.Button == MouseButtons.Right)
{
string s = Items[index].ToString();
Rectangle rect = GetItemRectangle(index);
tbox.Location = new Point(rect.X, rect.Y);
tbox.Size = new Size(rect.Width, rect.Height);
tbox.Text = s;
tbox.index = index;
tbox.SelectAll();
tbox.Show();
tbox.Focus();
}*/
}
base.OnMouseUp(e);
}
NTextBox tbox = new NTextBox();
class NTextBox : TextBox
{
public MultiLineListView mllb;
public int index = -1;
bool errshown = false;
bool brementer = false;
public NTextBox()
{
Multiline = true;
MaxLength = 2147483647;
MaximumSize = new System.Drawing.Size(0, 0);
WordWrap = false;
ScrollBars = ScrollBars.Both;
AcceptsReturn = true;
AcceptsTab = true;
}
protected override void OnKeyUp(KeyEventArgs e)
{
if (brementer)
{
Text = "";
brementer = false;
}
base.OnKeyUp(e);
}
protected override void OnKeyPress(KeyPressEventArgs e)
{
base.OnKeyPress(e);
}
protected override void OnLostFocus(System.EventArgs e)
{
if (Text.Trim() == "")
{
if (!errshown)
{
MessageBox.Show(
"Cannot enter NULL string as item!",
"Fatal error!", MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
errshown = false;
}
else
{
errshown = false;
mllb.Items[index] = Text;
Hide();
}
base.OnLostFocus(e);
}
}
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.KeyData == Keys.F2)
{
int index = SelectedIndex;
if (index == ListBox.NoMatches ||
index == 65535)
{
if (Items.Count > 0)
index = 0;
}
if (index != ListBox.NoMatches &&
index != 65535)
{
string s = Items[index].ToString();
Rectangle rect = GetItemRectangle(index);
tbox.Location = new Point(rect.X, rect.Y);
tbox.Size = new Size(rect.Width, rect.Height);
tbox.Text = s;
tbox.index = index;
tbox.SelectAll();
tbox.Show();
tbox.Focus();
}
}
base.OnKeyDown(e);
}
}
}
The difficulty I'm having, is that, even though I've set the textbox as it should be, the list view item still seems to be limiting content to TextWrap, and a maximum of 7.5 lines.
Image Reference http://imageshack.us/a/img819/9345/5nh4.png
On line 32 foreach (string line in s.Split(new string[] { Environment.NewLine }, StringSplitOptions.None)) I try to find the length of the longest line of text in the string to return in the OnMeasureItem override, but it refuses to go in excess of the assumed limit. Any help would be greatly appreciated.
You should take a look at a control called GlacialList. you can do such thing easily. Latest versions are not free but i used to use version 1.3. If you get to it there is a property that allow you to put ANY control inside a list cell. just add multiline textbox and your good to go
It may not be an option for you but if you want more Advanced UI features why not just switch to WPF where you get this built-in?

How to prevent user to enter a special character in text box?

I want to prevent one particular character * (asterisk) from being entered or pasted into a text box.
I tried:
key_press event - but it does not handle the case when user pastes an asterisk to the text box.
text_changed event - but when I remove the character, the cursor position goes back to the beginning of the text.
So I am wondering how to handle it, preferably in one event.
use the text changed event, but save the location of the cursor (the SelectionStart and SelectionEnd properties) before you remove the asterisk, then re set the cursor position (less the number of asterisks removed before the cursor).
private void textBox1_TextChanged(object sender, TextChangedEventArgs e)
{
var currentText = textBox1.Text;
var selectionStart = textBox1.SelectionStart;
var selectionLength = textBox1.SelectionLength;
int nextAsterisk;
while ((nextAsterisk = currentText.IndexOf('*')) != -1)
{
if (nextAsterisk < selectionStart)
{
selectionStart--;
}
else if (nextAsterisk < selectionStart + selectionLength)
{
selectionLength--;
}
currentText = currentText.Remove(nextAsterisk, 1);
}
if (textBox1.Text != currentText)
{
textBox1.Text = currentText;
textBox1.SelectionStart = selectionStart;
textBox1.SelectionLength = selectionLength;
}
}
This question may be of use to you. What you're looking for seems like either a MaskedTextBox or a TextBox with custom Validation logic. You should not simply erase an asterisk characters when it is input, because if a user has selected text, then typed an asterisk, they will have replaced the selected text with an asterisk before you have the chance to remove it.
You can set the cursor postion. For example:
textBox1.SelectionStart = textBox1.Text.Length;
EDIT:
Ok i took some time to write you a solution that works quite good. It keeps the edit cursor at the proper position and also covers the situation in which user pastes some * chars between chars.
int position = this.textBox1.SelectionStart;
string str = this.textBox1.Text;
int hit = 0;
for (int i = 0; i < position; i++)
{
if (str[i].Equals('*'))
hit++;
}
str = str.Replace("*", "");
this.textBox1.Text = str;
this.textBox1.SelectionLength = 0;
this.textBox1.SelectionStart = position - hit;
Here is the solution i found:-
On Text_changed event, here is what i am doing:-
txt1.Text = txt1.Text.Replace("*", string.Empty);
txt1.Select(txt1.Text.Length, 0);
Updated code:-
On Text_changed event:-
int curpos = 0;
bool isReplaced = false;
private void txt1_TextChanged(object sender, EventArgs e)
{
if (txt1.Text.Contains('*'))
{
curpos = txt1.SelectionStart;
isReplaced = true;
}
txt1.Text = txt1.Text.Replace("*", string.Empty);
if (isReplaced)
{
txt1.Select(curpos.Equals(0) ? 0 : curpos -1, 0);
isReplaced = false;
}
}
Final code and Tested :-
if (txt1.Text.Contains('*'))
{
foreach (char c in txt1.Text)
if (c.Equals('*'))
barredCharCount += 1;
curPosition = txt1.SelectionStart;
isTextReplaced = true;
}
txt1.Text = txt1.Text.Replace("*", string.Empty);
if (isTextReplaced)
{
txt1.Select(curPosition.Equals(0) ? 0 : curPosition - barredCharCount, 0);
isTextReplaced = false;
curPosition = barredCharCount = 0;
Console.Beep(); //does not work on 64 bit system
}
This piece of code is tested and working perfectly...

displaying line number in rich text box c#

I have a Multiline richtextbox control into which i want to integrate the feature of adding a line number. i have considered many approaches
Add a label and updating the line numbers as the line count changes
Add a picturebox along with to draw string on it.
Add another textbox along with and show line numbers on it
Add listbox along and display line numbers in it.
I got two doubts.
The richtextbox which i'm using is a custom made control and derieves from RichTextBox class. How can i add multiple controls to it.
What is the best approach to show line numbers for the multiline text in c#
My own example. All is fine, but wordwrap must be disabled :(
int maxLC = 1; //maxLineCount - should be public
private void rTB_KeyUp(object sender, KeyEventArgs e)
{
int linecount = rTB.GetLineFromCharIndex( rTB.TextLength ) + 1;
if (linecount != maxLC)
{
tB_line.Clear();
for (int i = 1; i < linecount+1; i++)
{
tB_line.AppendText(Convert.ToString(i) + "\n");
}
maxLC = linecount;
}
}
where rTB is my richtextbox and tB is textBox next to rTB
J.T. jr
this code helped me thank you, needed to convert visual basic but could:
Private Sub TextBox1_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles TextBox1.KeyUp
Dim maxlc As Integer = 1
Dim linecount As Integer = TextBox1.GetLineFromCharIndex(TextBox1.Height) + 1
If linecount <> maxlc Then
TextBox2.Clear()
For i = 0 To linecount - 1 Step 1
TextBox2.AppendText(Convert.ToString(i) + vbNewLine)
Next i
maxlc = linecount
End If
End Sub
public int getWidth()
{
int w = 25;
// get total lines of richTextBox1
int line = richTextBox1.Lines.Length;
if (line <= 99)
{
w = 20 + (int)richTextBox1.Font.Size;
}
else if (line <= 999)
{
w = 30 + (int)richTextBox1.Font.Size;
}
else
{
w = 50 + (int)richTextBox1.Font.Size;
}
return w;
}
public void AddLineNumbers()
{
// create & set Point pt to (0,0)
Point pt = new Point(0, 0);
// get First Index & First Line from richTextBox1
int First_Index = richTextBox1.GetCharIndexFromPosition(pt);
int First_Line = richTextBox1.GetLineFromCharIndex(First_Index);
// set X & Y coordinates of Point pt to ClientRectangle Width & Height respectively
pt.X = ClientRectangle.Width;
pt.Y = ClientRectangle.Height;
// get Last Index & Last Line from richTextBox1
int Last_Index = richTextBox1.GetCharIndexFromPosition(pt);
int Last_Line = richTextBox1.GetLineFromCharIndex(Last_Index);
// set Center alignment to LineNumberTextBox
LineNumberTextBox.SelectionAlignment = HorizontalAlignment.Center;
// set LineNumberTextBox text to null & width to getWidth() function value
LineNumberTextBox.Text = "";
LineNumberTextBox.Width = getWidth();
// now add each line number to LineNumberTextBox upto last line
for (int i = First_Line; i <= Last_Line + 2; i++)
{
LineNumberTextBox.Text += i + 1 + "\n";
}
}
private void Form1_Load(object sender, EventArgs e)
{
LineNumberTextBox.Font = richTextBox1.Font;
richTextBox1.Select();
AddLineNumbers();
}
private void richTextBox1_SelectionChanged(object sender, EventArgs e)
{
Point pt = richTextBox1.GetPositionFromCharIndex(richTextBox1.SelectionStart);
if (pt.X == 1)
{
AddLineNumbers();
}
}
private void richTextBox1_VScroll(object sender, EventArgs e)
{
LineNumberTextBox.Text = "";
AddLineNumbers();
LineNumberTextBox.Invalidate();
}
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
if (richTextBox1.Text == "")
{
AddLineNumbers();
}
}
private void richTextBox1_FontChanged(object sender, EventArgs e)
{
LineNumberTextBox.Font = richTextBox1.Font;
richTextBox1.Select();
AddLineNumbers();
}
private void LineNumberTextBox_MouseDown(object sender, MouseEventArgs e)
{
richTextBox1.Select();
LineNumberTextBox.DeselectAll();
}
private void Form1_Resize(object sender, EventArgs e)
{
AddLineNumbers();
}
WORKS 100%!!! But you need to add richTextBox2 for line numbers, if you want change it to other
form like listbox, anyway it served me well.
private void richTextBox1_keyDown(object sender, KeyEventArgs e)
{
for (int i = 0; i <= richTextBox1.Lines.Count(); i++)
{
if (!(e.KeyCode == Keys.Back))
{
if (!richTextBox2.Text.Contains(i.ToString()))
{
richTextBox2.Text += i.ToString() + "\n";
}
}
else
{
richTextBox2.Clear();
}
}
}

Categories

Resources