打印 RichTextBox
Printing RichTextBox
我正在制作一个简单的 WinForms 应用程序,我希望允许用户打印 RichTextBox 中的文本。
然后我关注了MSDN link..
它适用于一台真正的打印机(真正的我的意思是我可以触摸的打印机:))
但是如果我想使用某种 PDF 打印机怎么办?
那么我必须说它在 仅打印一页 时有效。
每下一页都打印在第一页上,这意味着文本被套印。
这很明显,但我能做些什么来强制 PDF 打印机创建新页面?
这是我的代码:
private PrintDocument docToPrint;
private string stringToPrint;
public mainForm()
{
InitializeComponent();
CenterToScreen();
this.docToPrint = new PrintDocument();
(...)
}
private void tsBtnPrint_Click(object sender, EventArgs e)
{
PrintDialog myPrintDialog = new PrintDialog();
myPrintDialog.AllowCurrentPage = true;
myPrintDialog.AllowSelection = true;
myPrintDialog.AllowSomePages = true;
myPrintDialog.Document = docToPrint;
if(myPrintDialog.ShowDialog()==DialogResult.OK)
{
StringReader reader = new StringReader(this.richTextBox.Text);
stringToPrint = reader.ReadToEnd();
this.docToPrint.PrintPage += new PrintPageEventHandler(this.docToPrintCustom);
this.docToPrint.Print();
}
}
private void docToPrintCustom(object sender, PrintPageEventArgs e)
{
Font PrintFont = this.richTextBox.Font;
SolidBrush PrintBrush = new SolidBrush(Color.Black);
int LinesPerPage = 0;
int charactersOnPage = 0;
e.Graphics.MeasureString(stringToPrint, PrintFont, e.MarginBounds.Size, StringFormat.GenericTypographic,
out charactersOnPage, out LinesPerPage);
e.Graphics.DrawString(stringToPrint, PrintFont, PrintBrush, e.MarginBounds, StringFormat.GenericTypographic);
stringToPrint = stringToPrint.Substring(charactersOnPage);
MessageBox.Show(stringToPrint.Length.ToString());
e.HasMorePages = (stringToPrint.Length > 0);
PrintBrush.Dispose();
}
我应该怎么做才能正确打印下一页?
您可以通过向 EM_FORMATRANGE
发送消息来打印 RuchTextBox
的内容。
This message is typically used to format the content of rich edit
control for an output device such as a printer.
要实施此解决方案,您可以执行以下步骤:
- 首先创建一个继承自
RichTextBox
的RichtextBoxEx
class并实现一个FormatRange
方法,其工作是打印控件内容的每一页。完整代码如下。
- 然后创建一个
Form
并在其上放置一个RichTextBoxEx
、PrintDocument
并处理BeginPrint
、PrintPage
和EndPrint
事件PrintDocument
并使用以下代码执行打印。
请注意
使用这种方式,您可以打印控件的内容并将所有格式应用于文本,这比使用一种字体和大小以黑色打印所有文本要好。您还可以将内容的字体和大小设置为一种字体、大小和颜色。
创建RichtextBoxEx
只是为了封装,完全是可选的,如果你想使用你现有的控件,只需使用我下面提供的FormatRange
方法的内容并将控件的属性传递给它以执行打印。
支持打印的RichTextBoxEx:
这是我上面描述的完整工作代码。代码摘自 msdn 文章 Getting WYSIWYG Print Results from a .NET RichTextBox Martin Müller 文章
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;
}
[DllImport("user32.dll")]
private static extern Int32 SendMessage(IntPtr hWnd, Int32 msg, Int32 wParam, IntPtr lParam);
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;
/// <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 = default(STRUCT_CHARRANGE);
cr.cpMin = charFrom;
cr.cpMax = charTo;
// Specify the area inside page margins
STRUCT_RECT rc = default(STRUCT_RECT);
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 = default(STRUCT_RECT);
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 = default(IntPtr);
hdc = e.Graphics.GetHdc();
// Fill in the FORMATRANGE structure
STRUCT_FORMATRANGE fr = default(STRUCT_FORMATRANGE);
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 = default(Int32);
if (measureOnly)
{
wParam = 0;
}
else
{
wParam = 1;
}
// Allocate memory for the FORMATRANGE struct and
// copy the contents of our struct to this memory
IntPtr lParam = default(IntPtr);
lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fr));
Marshal.StructureToPtr(fr, lParam, false);
// Send the actual Win32 message
int res = 0;
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 Convert.ToInt32(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);
}
}
用法示例:
private void printDocument1_BeginPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
{
// Start at the beginning of the text
firstCharOnPage = 0;
}
private void printDocument1_EndPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
{
// Clean up cached information
richTextBoxEx1.FormatRangeDone();
}
private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
firstCharOnPage = richTextBoxEx1.FormatRange(false, e, firstCharOnPage, richTextBoxEx1.TextLength);
// check if there are more pages to print
if (firstCharOnPage < richTextBoxEx1.TextLength)
e.HasMorePages = true;
else
e.HasMorePages = false;
}
private void printToolStripButton_Click(object sender, EventArgs e)
{
//Print the contents here
printDocument1.Print();
}
我正在制作一个简单的 WinForms 应用程序,我希望允许用户打印 RichTextBox 中的文本。
然后我关注了MSDN link.. 它适用于一台真正的打印机(真正的我的意思是我可以触摸的打印机:))
但是如果我想使用某种 PDF 打印机怎么办? 那么我必须说它在 仅打印一页 时有效。 每下一页都打印在第一页上,这意味着文本被套印。 这很明显,但我能做些什么来强制 PDF 打印机创建新页面?
这是我的代码:
private PrintDocument docToPrint;
private string stringToPrint;
public mainForm()
{
InitializeComponent();
CenterToScreen();
this.docToPrint = new PrintDocument();
(...)
}
private void tsBtnPrint_Click(object sender, EventArgs e)
{
PrintDialog myPrintDialog = new PrintDialog();
myPrintDialog.AllowCurrentPage = true;
myPrintDialog.AllowSelection = true;
myPrintDialog.AllowSomePages = true;
myPrintDialog.Document = docToPrint;
if(myPrintDialog.ShowDialog()==DialogResult.OK)
{
StringReader reader = new StringReader(this.richTextBox.Text);
stringToPrint = reader.ReadToEnd();
this.docToPrint.PrintPage += new PrintPageEventHandler(this.docToPrintCustom);
this.docToPrint.Print();
}
}
private void docToPrintCustom(object sender, PrintPageEventArgs e)
{
Font PrintFont = this.richTextBox.Font;
SolidBrush PrintBrush = new SolidBrush(Color.Black);
int LinesPerPage = 0;
int charactersOnPage = 0;
e.Graphics.MeasureString(stringToPrint, PrintFont, e.MarginBounds.Size, StringFormat.GenericTypographic,
out charactersOnPage, out LinesPerPage);
e.Graphics.DrawString(stringToPrint, PrintFont, PrintBrush, e.MarginBounds, StringFormat.GenericTypographic);
stringToPrint = stringToPrint.Substring(charactersOnPage);
MessageBox.Show(stringToPrint.Length.ToString());
e.HasMorePages = (stringToPrint.Length > 0);
PrintBrush.Dispose();
}
我应该怎么做才能正确打印下一页?
您可以通过向 EM_FORMATRANGE
发送消息来打印 RuchTextBox
的内容。
This message is typically used to format the content of rich edit control for an output device such as a printer.
要实施此解决方案,您可以执行以下步骤:
- 首先创建一个继承自
RichTextBox
的RichtextBoxEx
class并实现一个FormatRange
方法,其工作是打印控件内容的每一页。完整代码如下。 - 然后创建一个
Form
并在其上放置一个RichTextBoxEx
、PrintDocument
并处理BeginPrint
、PrintPage
和EndPrint
事件PrintDocument
并使用以下代码执行打印。
请注意
使用这种方式,您可以打印控件的内容并将所有格式应用于文本,这比使用一种字体和大小以黑色打印所有文本要好。您还可以将内容的字体和大小设置为一种字体、大小和颜色。
创建
RichtextBoxEx
只是为了封装,完全是可选的,如果你想使用你现有的控件,只需使用我下面提供的FormatRange
方法的内容并将控件的属性传递给它以执行打印。
支持打印的RichTextBoxEx:
这是我上面描述的完整工作代码。代码摘自 msdn 文章 Getting WYSIWYG Print Results from a .NET RichTextBox Martin Müller 文章
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;
}
[DllImport("user32.dll")]
private static extern Int32 SendMessage(IntPtr hWnd, Int32 msg, Int32 wParam, IntPtr lParam);
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;
/// <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 = default(STRUCT_CHARRANGE);
cr.cpMin = charFrom;
cr.cpMax = charTo;
// Specify the area inside page margins
STRUCT_RECT rc = default(STRUCT_RECT);
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 = default(STRUCT_RECT);
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 = default(IntPtr);
hdc = e.Graphics.GetHdc();
// Fill in the FORMATRANGE structure
STRUCT_FORMATRANGE fr = default(STRUCT_FORMATRANGE);
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 = default(Int32);
if (measureOnly)
{
wParam = 0;
}
else
{
wParam = 1;
}
// Allocate memory for the FORMATRANGE struct and
// copy the contents of our struct to this memory
IntPtr lParam = default(IntPtr);
lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fr));
Marshal.StructureToPtr(fr, lParam, false);
// Send the actual Win32 message
int res = 0;
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 Convert.ToInt32(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);
}
}
用法示例:
private void printDocument1_BeginPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
{
// Start at the beginning of the text
firstCharOnPage = 0;
}
private void printDocument1_EndPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
{
// Clean up cached information
richTextBoxEx1.FormatRangeDone();
}
private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
firstCharOnPage = richTextBoxEx1.FormatRange(false, e, firstCharOnPage, richTextBoxEx1.TextLength);
// check if there are more pages to print
if (firstCharOnPage < richTextBoxEx1.TextLength)
e.HasMorePages = true;
else
e.HasMorePages = false;
}
private void printToolStripButton_Click(object sender, EventArgs e)
{
//Print the contents here
printDocument1.Print();
}