|
|
|
|
|
Home
»
Printing in C#
»
Part I: Simple Color Syntax Code Editor for PHP written in C# and .NET
|
|
|
|
Author Rank :
|
|
|
Page Views :
|
80665
|
|
Downloads :
|
2462
|
|
Rating :
|
Rate it
|
|
Level :
|
Intermediate
|
|
|
|
|
Download
Files:
|
|
|
|
|
|
|
|
|
|
|
There are hundreds of editors to choose from out on the market(SlickEdit, CodeWright, Visual Studio, SharpDevelop), so the goal of this article is not to replace them, but to show you how to manipulate the RichEditBox to create color syntax as well as show you one way to print the RichEditBox to the printer. For some reason, I got caught up doing some PHP coding, so I decided to focus coloring this editor according to PHP, a popular and efficient language for scripting inside of HTML.

Figure 1. Print Preview of RichTextBox ColorSyntax Editor

Figure 2. The Color Syntax Editor Application
The Application is a simple Windows Form program that allows you to open and save the text files edited in the rich edit control, as well as print them out. The program takes advantage of a syntax text file for PHP which lists the functions and keywords contained in the PHP language. Below is a sample of the syntax file. The file consists of 3 headers: KEYWORDS, FUNCTIONS, and COMMENTS. The Application assigns colors to the keywords based on their specified category:
[KEYWORDS] echo int integer real php ......
[FUNCTIONS] sort strlen debugger_on debugger_off error_log phpinfo
[COMMENTS] // #
The file is read in using the ColorSyntaxEditor class shown as part of the design below. As seen in figure 3, the design consists of a Form class containing the GUI and FlickerFreeRichEditTextBox, a SyntaxReader class for reading language syntax from a file, and a WordAndPosition class used to hold information about words and positions of those words in the RichTextBox:

Figure 3. UML Design of Color Syntax Editor reverse engineered using WithClass UML Tool for C#
One thing you may be curious about is how do we assign different colors to individual words inside the RichTextBox? The way this is done is through a trick that selects the word we are interested in coloring and then assigns a color to the selection (you can also assign a font to the selection if you wish):
Listing 1. Coloring in a Selection in the RichTextBox
Color c = Lookup(wp.Word); richTextBox1.Select(wp.Position, wp.Length); richTextBox1.SelectionColor = c;
Editing the text has the following use case it uses to change the color:
- Event Handler traps that the RichTextBox text has changed.
- Parse the current line of text that the cursor is sitting on.
- Parse each word in the line using a Regular Expression object and save words in an array.
- Select each parsed word and color according to the ColorSyntaxEditor .
Below is the method that implements this use case:
Listing 2. Coloring in words and symbols on the current line
private void MakeColorSyntaxForCurrentLine() { // Store current cursor position int CurrentSelectionStart = richTextBox1.SelectionStart; int CurrentSelectionLength = richTextBox1.SelectionLength; // find start of line int pos = CurrentSelectionStart; while ( (pos > 0) && (richTextBox1.Text[pos-1] != '\n')) pos--; // find end of line int pos2 = CurrentSelectionStart; while ( (pos2 < richTextBox1.Text.Length) && (richTextBox1.Text[pos2] != '\n') ) pos2++; string s = richTextBox1.Text.Substring(pos, pos2 - pos); // Parse the line into individual symbols and words int count = ParseLine(s); // Loop through each word, select, and color according to // Lookup function which calls the SyntaxReader for (int i = 0; i < count; i++) { WordAndPosition wp = TheBuffer[i]; Color c = Lookup(wp.Word); richTextBox1.Select(wp.Position + pos, wp.Length); richTextBox1.SelectionColor = c; } // Restore Cursor if (CurrentSelectionStart >=0) richTextBox1.Select(CurrentSelectionStart, CurrentSelectionLength); }
Comments of course need to be handled a bit differently so a comment case looks like the following:
- TextChanged Event Handler traps RichTextBox event
- Extract the current line that the cursor sits on
- if next symbol is a comment, color the entire line to the comment color
The code for coloring the comment is shown below:
Listing 3. Coloring in comments in the RichTextBox
// check if its a C++ style comment if (wp.Word == "/" && previousWord == "/") { // color until end of line int posCommentStart = wp.Position - 1; posCommentEnd = pos2; // pos2 was determined in the previous // code as being the last char position // in the line richTextBox1.Select(posCommentStart + pos, posCommentEnd - (posCommentStart + pos)); richTextBox1.SelectionColor = this.kCommentColor; }
How do we parse the words in a line? The words of code need to be parsed using a regular expression that pulls out entire words such as(php, echo, var) as an element to color and symbols (such as .;?+) as an element to color. The regular expression that does this is shown in the code below:
Listing 4. A regular expression for parsing words and symbols
Regex r = new Regex(@"\w+|[^A-Za-z0-9_ \f\t\v]", RegexOptions.IgnoreCase|RegexOptions.Compiled);
This line of code creates a regular expression object that accepts either words or symbols. The alphanumeric words are filtered in using the \w expression. The symbols are filtered in using the [^A-Za-z0-9 \f\t\v] expression which basically says only accept a single character that is not any alpha numeric or white space characters.
The code for parsing a line into words and symbols and their corresponding positions is shown below:
Listing 5. Matching the regular expression against the words in the line of code
private int ParseLine(string s) { // Clear out the Array of code words TheBuffer.Initialize(); int count = 0; // Create the regular expression object to match against the string Regex r = new Regex(@"\w+|[^A-Za-z0-9_ \f\t\v]", RegexOptions.IgnoreCase|RegexOptions.Compiled); Match m; // Loop through the string and continue to record // words and symbols and their corresponding positions and lengths for (m = r.Match(s); m.Success ; m = m.NextMatch()) { TheBuffer[count].Word = m.Value; TheBuffer[count].Position = m.Index; TheBuffer[count].Length = m.Length; // Console.WriteLine("Next Word = " + m.Value); count++; } // return the number of symbols and words return count; }
Reducing the Flicker
A few individuals have been kind enough to e-mail me a solution on how to reduce the flicker in this application (Mark Mihevc & JACK DUNN) and I just wanted to take the opportunity in this article to thank them. In order to reduce the flicker of the RichTextBox, we simply subclass the RichTextBox class with our own called FlickerFreeRichEditTextBox. Then we override the WndProc method in this class to give us control over when the WM_PAINT message is passed into the class. The entire subclass of the rich text box control is shown below:
Listing 6. Subclassing the RichTextBox to reduce flicker in the control
using System; using System.Windows.Forms; namespace ColorSyntaxEditor { /// <summary> /// Summary description for FlickerFreeRichEditTextBox - Subclasses the RichTextBox to allow control over flicker /// </summary> public class FlickerFreeRichEditTextBox : RichTextBox { const short WM_PAINT = 0x00f; public FlickerFreeRichEditTextBox() { } public static bool _Paint = true; protected override void WndProc(ref System.Windows.Forms.Message m) { // Code courtesy of Mark Mihevc // sometimes we want to eat the paint message so we don't have to see all the // flicker from when we select the text to change the color. if (m.Msg == WM_PAINT) { if (_Paint)base.WndProc(ref m); // if we decided to paint this control, just call the RichTextBox WndProc else m.Result = IntPtr.Zero; // not painting, must set this to IntPtr.Zero if not painting otherwise serious problems. } else base.WndProc (ref m); // message other than WM_PAINT, jsut do what you normally do. } } }
To use the control above, simply change the static _Paint variable to false when we select and color the text and turn it back to true when we are done. Walla! The flicker disappears. Below are the calls in our code that toggles the _Paint flag in the RichTextBox's TextChanged Event Handler inside our Form.
Listing 7. Toggling the Paint flag of the subclassed RichTextBox to reduce flicker
private void richTextBox1_TextChanged(object sender, System.EventArgs e) { if (populating) return; ColorSyntaxEditor.FlickerFreeRichEditTextBox._Paint = false; // turn off flag to ignore WM_PAINT messages MakeColorSyntaxForCurrentLine(); ColorSyntaxEditor.FlickerFreeRichEditTextBox._Paint = true; // restore flag so we can paint the control }
Part II - Printing the RichTextBox
We can some of the same techniques previously mentioned in this article to help us in printing out the rich text box. Remember from previous articles in C# Corner on printing that all printing is performed from the PrintPage EventHandler produced by double clicking on the printDocument1 component. (See Printing in C#). From the PrintPage event handler, we can get a handle to the device context of the printer. We then pass this Graphics object to our GDI+ method that prints the RichEditControl.
private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e) { // Get device context for the printer Graphics g = e.Graphics; // Pass the device context to the function that // draws the RichTextBox to the printer lastChar = DrawEditControl(g, lastChar); if (lastChar != -1) e.HasMorePages = true; else { e.HasMorePages = false; lastChar = 0; } }
Note also that this method checks to see if we have multiple pages to print. If we do, the HasMorePages is set to true and the PrintPage event will be triggered again. Now lets take a look at the DrawEditControl method which renders the contents of the RichTextBox control:
private int lastChar = 0; private int DrawEditControl(Graphics g, int lastChar) { // draw the control by selecting each character and deterimining its // color int xPos = 10; int yPos = 40; int kMargin = 50; // start from the last position of the previous page for (int c = lastChar; c < richTextBox1.Text.Length; c++) { // Select a single character and retrieve the color and font richTextBox1.Select(c,1); char nextChar = richTextBox1.Text[c]; Color theColor = richTextBox1.SelectionColor; Font theFont = richTextBox1.SelectionFont; // Determine the character height from the font int height = theFont.Height; // if the next character is a return character, increment the Y // Position if (nextChar == '\n') { // add to height on return characters yPos += (height + 3); xPos = 10; // Get the height of the default print page int paperHeight = printDocument1.PrinterSettings. DefaultPageSettings.PaperSize.Height; // Test to see if we went past the bottom margin of the page if (yPos > paperHeight - kMargin) return c; } // if the next character is a space or tab, increment the horizontal // position by half the height else if ((nextChar == ' ') || (nextChar == '\t')) { xPos += theFont.Height/2; } else { Regex r = new Regex(@"\w", RegexOptions.IgnoreCase|RegexOptions.Compiled); Match m; string nextWord = ""; bool reduceAtEnd = false; m = r.Match(nextChar.ToString()); // Determine if next character is alpha numeric if (m.Success) reduceAtEnd = true; else nextWord = nextChar.ToString(); // use a regular expression matching alphanumerics // until a whole word is formed // by printing the whole word, rather than individual // characters, this way the characters will be spaced // better in the printout while (m.Success) { nextWord += nextChar; c++; nextChar = richTextBox1.Text[c]; m = r.Match(nextChar.ToString()); } if (reduceAtEnd) { c--; } // Draw the string at the current x position with the current font // and current selection color g.DrawString(nextWord, theFont, new SolidBrush(theColor), xPos, yPos); // Measure the length of the string to see where to advance the next // horizontal position SizeF thesize = g.MeasureString(nextWord, theFont); // Increment the x position by the size of the word xPos += (int)thesize.Width - 4; } } // All characters in the RichTextBox have been visited, return -1 return -1; }
The code above goes character by character in the RichEditBox, selects the character, and uses the selection to determine the color and font. The characters are rendered to the printer using the Graphics method DrawString. Whole words are grouped using a regular expression before being sent to draw string to make a more aesthetic and accurately portrayed print representation. The cursor is advanced either horizontally or vertically according to the current character. Return characters will advance the current drawing position vertically to the beginning of the next line. All other characters advance the current drawing position horizontally.
Conclusions and Observations
The color syntax editor for PHP is a simple tool to help you understand how to utilize the RichTextBox control. You can edit the syntax file read by the SyntaxReader class to support C#, C++, Java, VB or any language you want. It would be nice to have a way of setting a characters color in the rich edit control according to position rather than selection. I noticed also that the rich edit control can be streamed out into a file that maintains its color and font information. This probably would be a nice future feature for this app.
|
|
Comment Request!
Thank you for reading this post. Please post your feedback, question, or comments about this post
Here.
|
|
|
|
|
Login
to add your contents and source code to this article
|
|
|
|
|
|
|
|
|
|
|
|
Mike Gold
Michael Gold is President of Microgold Software Inc., makers of the WithClass UML Tool. His company is a Microsoft VBA Partner and Borland Partner. Mike is a Microsoft MVP and founding member of C# Corner. He has a BSEE and MEng EE from Cornell University and has consulted for Chase Manhattan Bank, JP Morgan, Merrill Lynch, and Charles Schwab. Currently he is a senior developer at Finisar Corp. He has been involved in several .NET book projects, and is currently working on a book for using .NET with embedded systems.
He can be reached at mike@c-sharpcorner.com
|
|
|
|
|
|
|
|
|
C# Consulting is founded in 2002 by the founders of C# Corner. Unlike a traditional
consulting company, our consultants are well-known experts in .NET and many of them
are MVPs, authors, and trainers. We specialize in Microsoft .NET development and
utilize Agile Development and Extreme Programming practices to provide fast pace
quick turnaround results. Our software development model is a mix of Agile Development,
traditional SDLC, and Waterfall models.
|
|
Click here to learn more about C# Consulting. |
|
|
|
|
|
|
|
Introducing MaxV - one click. infinite control. Hyper-V Hosting from MaximumASP.
Finally – a virtual platform that delivers next-generation Windows Server 2008 Hyper-V virtualization technology from a managed hosting partner you can truly depend on. Visit www.maximumasp.com/max for a FREE 30 day trial. Hurry offer ends soon.
Climb aboard the MaxV platform and take advantage of High Availability, Intelligent Monitoring, Recurrent Backups, and Scalability – with no hassle or hidden fees.
As a managed hosting partner focused solely on Microsoft technologies since 2000, MaximumASP is uniquely qualified to provide the superior support that our business is built on. Unparalleled expertise with Microsoft technologies lead to working directly with Microsoft as first to offer IIS 7 and SQL 2008 betas in a hosted environment; partnering in the Go Live Program for Hyper-V; and product co-launches built on WS 2008 with Hyper-V technology.
|
Dynamic PDF
ceTE software specializes in components for dynamic PDF generation and manipulation. The DynamicPDF™ product line allows you to dynamically generate PDF documents, merge PDF documents and new content to existing PDF documents from within your applications.
|
Nevron Chart for .NET 2010.1 Now Available
The leading .NET charting control now features PDF, Flash and Silverlight export, visualization of large datasets and more. Deliver true charting functionality to your BI, Scorecard, Presentation or Scientific apps. Download evaluation now.
|
ASP.NET 4 Hosting
Get 2 Months Free of ASP.NET Hosting for Only $4.95/month! Receive FREE MS SQL and MySQL Databases Including ASP.NET 4/3.5, MVC 3.0, Silverlight 4, Windows 2008/IIS 7.0 Plus FREE IIS 7 Modules. Host UNLIMITED ASP.NET Web Sites – Click Here!
|
|
|
|
|
|
|
|
|
|
|
|
|