1、继承RichTextBox,创建
using
System;
using
System.Windows.Forms;
using
System.Drawing;
using
System.Runtime.InteropServices;
using
System.Drawing.Printing;
/**/
/// <summary>
/// An extension for RichTextBox suitable for printing.
/// </summary>
public
class
RichTextBoxEx : RichTextBox
...
{
[StructLayout(LayoutKind.Sequential)]
private struct STRUCT_RECT
...{
public Int32 left;
public Int32 top;
public Int32 right;
public Int32 bottom;
}
[StructLayout(LayoutKind.Sequential)]
private struct STRUCT_CHARRANGE
...{
public Int32 cpMin;
public Int32 cpMax;
}
[StructLayout(LayoutKind.Sequential)]
private struct STRUCT_FORMATRANGE
...{
public IntPtr hdc;
public IntPtr hdcTarget;
public STRUCT_RECT rc;
public STRUCT_RECT rcPage;
public STRUCT_CHARRANGE chrg;
}
[StructLayout(LayoutKind.Sequential)]
private struct CHARFORMATSTRUCT
...{
public int cbSize;
public UInt32 dwMask;
public UInt32 dwEffects;
public Int32 yHeight;
public Int32 yOffset;
public Int32 crTextColor;
public byte bCharSet;
public byte bPitchAndFamily;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public char[] szFaceName;
}
[DllImport("user32.dll")]
private static extern Int32 SendMessage(IntPtr hWnd, Int32 msg,
Int32 wParam, IntPtr lParam);
// Windows Messages defines
private const Int32 WM_USER = 0x400;
private const Int32 EM_FORMATRANGE = WM_USER + 57;
private const Int32 EM_GETCHARFORMAT = WM_USER + 58;
private const Int32 EM_SETCHARFORMAT = WM_USER + 68;
// Defines for EM_SETCHARFORMAT/EM_GETCHARFORMAT
private const Int32 SCF_SELECTION = 0x0001;
private const Int32 SCF_WORD = 0x0002;
private const Int32 SCF_ALL = 0x0004;
// Defines for STRUCT_CHARFORMAT member dwMask
private const UInt32 CFM_BOLD = 0x00000001;
private const UInt32 CFM_ITALIC = 0x00000002;
private const UInt32 CFM_UNDERLINE = 0x00000004;
private const UInt32 CFM_STRIKEOUT = 0x00000008;
private const UInt32 CFM_PROTECTED = 0x00000010;
private const UInt32 CFM_LINK = 0x00000020;
private const UInt32 CFM_SIZE = 0x80000000;
private const UInt32 CFM_COLOR = 0x40000000;
private const UInt32 CFM_FACE = 0x20000000;
private const UInt32 CFM_OFFSET = 0x10000000;
private const UInt32 CFM_CHARSET = 0x08000000;
// Defines for STRUCT_CHARFORMAT member dwEffects
private const UInt32 CFE_BOLD = 0x00000001;
private const UInt32 CFE_ITALIC = 0x00000002;
private const UInt32 CFE_UNDERLINE = 0x00000004;
private const UInt32 CFE_STRIKEOUT = 0x00000008;
private const UInt32 CFE_PROTECTED = 0x00000010;
private const UInt32 CFE_LINK = 0x00000020;
private const UInt32 CFE_AUTOCOLOR = 0x40000000;
/**//// <summary>
/// Calculate or render the contents of our RichTextBox for printing
/// </summary>
/// <param name="measureOnly">If true, only the calculation is performed,
/// otherwise the text is rendered as well</param>
/// <param name="e">The PrintPageEventArgs object from the
/// PrintPage event</param>
/// <param name="charFrom">Index of first character to be printed</param>
/// <param name="charTo">Index of last character to be printed</param>
/// <returns>(Index of last character that fitted on the
/// page) + 1</returns>
public int FormatRange(bool measureOnly, PrintPageEventArgs e,
int charFrom, int charTo)
...{
// Specify which characters to print
STRUCT_CHARRANGE cr;
cr.cpMin = charFrom;
cr.cpMax = charTo;
// Specify the area inside page margins
STRUCT_RECT rc;
rc.top = HundredthInchToTwips(e.MarginBounds.Top);
rc.bottom = HundredthInchToTwips(e.MarginBounds.Bottom);
rc.left = HundredthInchToTwips(e.MarginBounds.Left);
rc.right = HundredthInchToTwips(e.MarginBounds.Right);
// Specify the page area
STRUCT_RECT rcPage;
rcPage.top = HundredthInchToTwips(e.PageBounds.Top);
rcPage.bottom = HundredthInchToTwips(e.PageBounds.Bottom);
rcPage.left = HundredthInchToTwips(e.PageBounds.Left);
rcPage.right = HundredthInchToTwips(e.PageBounds.Right);
// Get device context of output device
IntPtr hdc = e.Graphics.GetHdc();
// Fill in the FORMATRANGE struct
STRUCT_FORMATRANGE fr;
fr.chrg = cr;
fr.hdc = hdc;
fr.hdcTarget = hdc;
fr.rc = rc;
fr.rcPage = rcPage;
// Non-Zero wParam means render, Zero means measure
Int32 wParam = (measureOnly ? 0 : 1);
// Allocate memory for the FORMATRANGE struct and
// copy the contents of our struct to this memory
IntPtr lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fr));
Marshal.StructureToPtr(fr, lParam, false);
// Send the actual Win32 message
int res = SendMessage(Handle, EM_FORMATRANGE, wParam, lParam);
// Free allocated memory
Marshal.FreeCoTaskMem(lParam);
// and release the device context
e.Graphics.ReleaseHdc(hdc);
return res;
}
/**//// <summary>
/// Convert between 1/100 inch (unit used by the .NET framework)
/// and twips (1/1440 inch, used by Win32 API calls)
/// </summary>
/// <param name="n">Value in 1/100 inch</param>
/// <returns>Value in twips</returns>
private Int32 HundredthInchToTwips(int n)
...{
return (Int32)(n * 14.4);
}
/**//// <summary>
/// Free cached data from rich edit control after printing
/// </summary>
public void FormatRangeDone()
...{
IntPtr lParam = new IntPtr(0);
SendMessage(Handle, EM_FORMATRANGE, 0, lParam);
}
/**//// <summary>
/// Sets the font size only for the selected part of the rich text box
/// without modifying the other properties like font or style
/// </summary>
/// <param name="size">new point size to use</param>
/// <returns>true on success, false on failure</returns>
public bool SetSelectionSize(int size)
...{
CHARFORMATSTRUCT cf = new CHARFORMATSTRUCT();
cf.cbSize = Marshal.SizeOf(cf);
cf.dwMask = CFM_SIZE;
// yHeight is in 1/20 pt
cf.yHeight = size * 20;
IntPtr lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(cf));
Marshal.StructureToPtr(cf, lParam, false);
int res = SendMessage(Handle, EM_SETCHARFORMAT, SCF_SELECTION, lParam);
return (res == 0);
}
/**//// <summary>
/// Sets the bold style only for the selected part of the rich text box
/// without modifying the other properties like font or size
/// </summary>
/// <param name="bold">make selection bold (true) or regular (false)</param>
/// <returns>true on success, false on failure</returns>
public bool SetSelectionBold(bool bold)
...{
return SetSelectionStyle(CFM_BOLD, bold ? CFE_BOLD : 0);
}
/**//// <summary>
/// Sets the italic style only for the selected part of the rich text box
/// without modifying the other properties like font or size
/// </summary>
/// <param name="italic">make selection italic (true) or regular (false)</param>
/// <returns>true on success, false on failure</returns>
public bool SetSelectionItalic(bool italic)
...{
return SetSelectionStyle(CFM_ITALIC, italic ? CFE_ITALIC : 0);
}
/**//// <summary>
/// Sets the underlined style only for the selected part of the rich text box
/// without modifying the other properties like font or size
/// </summary>
/// <param name="underlined">make selection underlined (true) or regular (false)</param>
/// <returns>true on success, false on failure</returns>
public bool SetSelectionUnderlined(bool underlined)
...{
return SetSelectionStyle(CFM_UNDERLINE, underlined ? CFE_UNDERLINE : 0);
}
/**//// <summary>
/// Set the style only for the selected part of the rich text box
/// with the possibility to mask out some styles that are not to be modified
/// </summary>
/// <param name="mask">modify which styles?</param>
/// <param name="effect">new values for the styles</param>
/// <returns>true on success, false on failure</returns>
private bool SetSelectionStyle(UInt32 mask, UInt32 effect)
...{
CHARFORMATSTRUCT cf = new CHARFORMATSTRUCT();
cf.cbSize = Marshal.SizeOf(cf);
cf.dwMask = mask;
cf.dwEffects = effect;
IntPtr lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(cf));
Marshal.StructureToPtr(cf, lParam, false);
int res = SendMessage(Handle, EM_SETCHARFORMAT, SCF_SELECTION, lParam);
return (res == 0);
}
}
新类RichTextBoxEx
2、初始化,
private RichTextBoxEx RTBBook;
RTBBook = new RichTextBoxEx();
RTBBook.Parent = this..Panel2;
RTBBook.Dock = DockStyle.Fill;
3、增加 printDocument控件
4、设置printDocument的事件
private int m_nFirstCharOnPage;
private void printDocument_BeginPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
{
m_nFirstCharOnPage = 0;
}
private void printDocument_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
// To print the boundaries of the current page margins
// uncomment the next line:
//e.Graphics.DrawRectangle(System.Drawing.Pens.Blue, e.MarginBounds);
// make the RTBBook calculate and render as much text as will
// fit on the page and remember the last character printed for the
// beginning of the next page
m_nFirstCharOnPage = RTBBook.FormatRange(false,
e,
m_nFirstCharOnPage,
RTBBook.TextLength);
// check if there are more pages to print
if (m_nFirstCharOnPage < RTBBook.TextLength)
e.HasMorePages = true;
else
e.HasMorePages = false;
}
private void printDocument_EndPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
{
RTBBook.FormatRangeDone();
}
5、预览
private void 打印预览VToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
PrintPreviewDialog printPreviewDialog1 = new PrintPreviewDialog();
printPreviewDialog1.Document = printDocument;
printPreviewDialog1.FormBorderStyle = FormBorderStyle.Fixed3D;
printPreviewDialog1.ShowDialog(this);
}
catch (Exception excep)
{
MessageBox.Show(excep.Message, "打印出错", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
6、打印
private void 打印PToolStripMenuItem_Click(object sender, EventArgs e)
{
printDocument.Print();
}
参考;MSDN