ezimmerman
October 14th, 2009, 01:15 PM
I want to make a "view only" rich text box.
fyi:
I am deriving a new class from RichTextBox
I've set the ReadOnly property to true.
Is there a way to prevent selection of items?
Is there a way to remove the blinking cursor?
JonnyPoet
October 14th, 2009, 02:24 PM
I want to make a "view only" rich text box.
fyi:
I am deriving a new class from RichTextBox
I've set the ReadOnly property to true.
Is there a way to prevent selection of items?
Is there a way to remove the blinking cursor?
Instead of using the RTB directly use it and do it ownerdrawn. Then use something as a canvas where you draw the RTB output.
No selection possible, no access to the data. Not necessary to make it read only. No cursor
Here is the class I'm using
/// <summary>
/// Ownerdrawn Richtextbox not zoomable
/// </summary>
public class RichTextBoxPrintCtrl:RichTextBox{
//Convert the unit used by the .NET framework (1/100 inch) 0.254 mm)
//and the unit used by Win32 API calls (twips 1/1440 inch)
// 1 mm = 56,6928 twip
private const double anInch = 14.4;
[StructLayout(LayoutKind.Sequential)]
private struct RECT {
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[StructLayout(LayoutKind.Sequential)]
private struct CHARRANGE {
public int cpMin; //First character of range (0 for start of doc)
public int cpMax; //Last character of range (-1 for end of doc)
}
[StructLayout(LayoutKind.Sequential)]
private struct FORMATRANGE {
public IntPtr hdc; //Actual DC to draw on
public IntPtr hdcTarget; //Target DC for determining text formatting
public RECT rc; //Region of the DC to draw to (in twips)
public RECT rcPage; //Region of the whole DC (page size) (in twips)
public CHARRANGE chrg; //Range of text to draw (see earlier declaration)
}
private const int WM_USER = 0x0400;
private const int EM_FORMATRANGE = WM_USER + 57;
[DllImport("USER32.dll")]
private static extern IntPtr SendMessage (IntPtr hWnd , int msg , IntPtr wp, IntPtr lp);
// Renders the contents of the RichTextBox for printing
// Return the last character printed + 1 (printing start from this point for next page)
/// <summary>
/// Prints the RTB in the devicecontext
/// Margin sizes needs to be done in the PrintPageEvents
/// </summary>
/// <param name="charFrom"></param>
/// <param name="charTo"></param>
/// <param name="e"></param>
/// <returns></returns>
public int Print( int charFrom, int charTo,PrintPageEventArgs e) {
//Calculate the area to render and print
RECT rectToPrint;
rectToPrint.Top = (int)(e.MarginBounds.Top * anInch);
rectToPrint.Bottom = (int)(e.MarginBounds.Bottom * anInch);
rectToPrint.Left = (int)(e.MarginBounds.Left * anInch);
rectToPrint.Right = (int)(e.MarginBounds.Right * anInch);
//Calculate the size of the page
RECT rectPage;
rectPage.Top = (int)(e.PageBounds.Top * anInch);
rectPage.Bottom = (int)(e.PageBounds.Bottom * anInch);
rectPage.Left = (int)(e.PageBounds.Left * anInch);
rectPage.Right = (int)(e.PageBounds.Right * anInch);
Graphics g = e.Graphics;
IntPtr res = Draw(charFrom, charTo, ref rectToPrint, ref rectPage, g);
//Return last + 1 character printer
return res.ToInt32();
}
/// <summary>
/// The internal Draw method that draws the RTB Text in WYSIWYG Format.
/// </summary>
/// <param name="charFrom"></param>
/// <param name="charTo"></param>
/// <param name="rectToPrint"></param>
/// <param name="rectPage"></param>
/// <param name="g"></param>
/// <returns></returns>
private IntPtr Draw(int charFrom, int charTo, ref RECT rectToPrint, ref RECT rectPage, Graphics g) {
IntPtr hdc = g.GetHdc();
FORMATRANGE fmtRange;
fmtRange.chrg.cpMax = charTo; //Indicate character from to character to
fmtRange.chrg.cpMin = charFrom;
fmtRange.hdc = hdc; //Use the same DC for measuring and rendering
fmtRange.hdcTarget = hdc; //Point at printer hDC
fmtRange.rc = rectToPrint; //Indicate the area on page to print
fmtRange.rcPage = rectPage; //Indicate size of page
IntPtr res = IntPtr.Zero;
IntPtr wparam = IntPtr.Zero;
wparam = new IntPtr(1);
//Get the pointer to the FORMATRANGE structure in memory
IntPtr lparam = IntPtr.Zero;
lparam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fmtRange));
Marshal.StructureToPtr(fmtRange, lparam, false);
//Send the rendered data for printing
res = SendMessage(Handle, EM_FORMATRANGE, wparam, lparam);
//Free the block of memory allocated
Marshal.FreeCoTaskMem(lparam);
//Release the device context handle obtained by a previous call
g.ReleaseHdc(hdc);
return res;
}
/// <summary>
/// Draws the RTB as it is by use of the Graphics adapter of the canvas. Sizes in Twips
/// </summary>
/// <param name="recInner"></param>
/// <param name="recDoc"></param>
/// <param name="g"></param>
public void DrawRTBText( int width, int height, Rectangle recMargin, Rectangle recDoc, Graphics g) {
RECT rectToPrint;
this.Width = width;
this.Height = height;
rectToPrint.Left = recMargin.Left;
rectToPrint.Right = recMargin.Width+ recMargin.Left;
rectToPrint.Top = recMargin.Top;
rectToPrint.Bottom = recMargin.Top + recMargin.Height;
RECT rectPage;
rectPage.Left = recDoc.Left;
rectPage.Top = recDoc.Top;
rectPage.Right = recDoc.Left + recDoc.Width;
rectPage.Bottom = recDoc.Top + recDoc.Height;
int len = this.Text.Length;
Draw(0, len, ref rectToPrint, ref rectPage, g);
}
}
ezimmerman
October 14th, 2009, 02:32 PM
How do I do that?
JonnyPoet
October 14th, 2009, 03:11 PM
How do I do that?Simple use for example a picturebox as the canvas and the class I provided as the RTB class. The picturebox has the possibillity to ownerdraw so in that drawing method use call the DrawRTBText method of the derived RTB class.
So after you have filled your RTB with data simple invalidate the Picturebox so it will call its draw method, which will call the DrawRTBTex mmethod. The RTB is drawn on the canvas then (in the picturebox) In my case this looks like the picture in the bottom. ( BTW The text is simple an example its a word doc loaded into that RTB and as I also did some rulers it also looks like word, but it is an ownerdrawn RTB.) The text is a letter talking to a friend about a learning project and if people would be interested into a project like that. )
ezimmerman
October 14th, 2009, 04:48 PM
Brilliant, but how are you loading it so you still get scrollbars?
What does your pictureBox paint handler look like?
Thanks again!
Eric
JonnyPoet
October 15th, 2009, 12:33 PM
Lokk at this page
http://www.codeproject.com/KB/cs/BizDraw__for_net.aspx?msg=3104702#xx3104702xx
When you modify that code as I did then you can use that RTB together wiz the canvas created by that control.
Read the comments too and especially look for the corrections of code I did as 'nussknacker' there