打印富文本框

Paw*_*ęba 4 .net c# printing richtextbox winforms

我正在制作一个简单的 WinForms 应用程序,我想允许用户从 RichTextBox 打印文本。

然后我按照MSDN链接..它适用于真正的打印机(真正的我的意思是我可以触摸的:))

但是如果我想使用某种 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();
        }
Run Code Online (Sandbox Code Playgroud)

我应该怎样做才能以正确的方式打印下一页?

Rez*_*aei 7

您可以通过向其RuchTextBox发送消息来打印您的内容。EM_FORMATRANGE

\n
\n

此消息通常用于格式化输出设备(例如打印机)的丰富编辑\n控件的内容。

\n
\n

要实施此解决方案,您可以执行以下步骤:

\n
    \n
  • 首先创建一个RichtextBoxEx继承RichTextBox并实现一个FormatRange方法的类,该方法的工作是打印控件内容的每一页。完整的代码如下所示。
  • \n
  • 然后创建一个Form并在其上放置一个RichTextBoxEx,PrintDocument并处理BeginPrint,PrintPageEndPrint的事件PrintDocument并使用以下代码执行打印。
  • \n
\n

请注意

\n
    \n
  1. 使用这种方式,您可以打印控件的内容,并将所有格式应用于文本,这比使用一种字体和大小以黑色打印所有文本更好。您还可以将内容的字体和大小设置为一种字体、大小和颜色。

    \n
  2. \n
  3. 创建RichtextBoxEx只是为了封装,并且完全是可选的,如果您想使用现有的控件,只需使用FormatRange我在下面提供的方法的内容并将控件的属性传递给它来执行打印即可。

    \n
  4. \n
\n

支持打印的RichTextBoxEx:

\n

这是我上面描述的完整工作代码。该代码摘自 Martin M\xc3\xbcller 撰写的 msdn 文章Getting WYSIWYG Print Results from a .NET RichTextBox文章。

\n
public class RichTextBoxEx : RichTextBox\n{\n    [StructLayout(LayoutKind.Sequential)]\n    private struct STRUCT_RECT\n    {\n        public Int32 left;\n        public Int32 top;\n        public Int32 right;\n        public Int32 bottom;\n    }\n\n    [StructLayout(LayoutKind.Sequential)]\n    private struct STRUCT_CHARRANGE\n    {\n        public Int32 cpMin;\n        public Int32 cpMax;\n    }\n\n    [StructLayout(LayoutKind.Sequential)]\n    private struct STRUCT_FORMATRANGE\n    {\n        public IntPtr hdc;\n        public IntPtr hdcTarget;\n        public STRUCT_RECT rc;\n        public STRUCT_RECT rcPage;\n        public STRUCT_CHARRANGE chrg;\n    }\n\n    [DllImport("user32.dll")]\n    private static extern Int32 SendMessage(IntPtr hWnd, Int32 msg, Int32 wParam, IntPtr lParam);\n\n    private const Int32 WM_USER = 0x400;\n    private const Int32 EM_FORMATRANGE = WM_USER + 57;\n    private const Int32 EM_GETCHARFORMAT = WM_USER + 58;\n    private const Int32 EM_SETCHARFORMAT = WM_USER + 68;\n\n    /// <summary>\n    /// Calculate or render the contents of our RichTextBox for printing\n    /// </summary>\n    /// <param name="measureOnly">If true, only the calculation is performed, otherwise the text is rendered as well</param>\n    /// <param name="e">The PrintPageEventArgs object from the PrintPage event</param>\n    /// <param name="charFrom">Index of first character to be printed</param>\n    /// <param name="charTo">Index of last character to be printed</param>\n    /// <returns> (Index of last character that fitted on the page) + 1</returns>\n    public int FormatRange(bool measureOnly, PrintPageEventArgs e, int charFrom, int charTo)\n    {\n        // Specify which characters to print\n        STRUCT_CHARRANGE cr = default(STRUCT_CHARRANGE);\n        cr.cpMin = charFrom;\n        cr.cpMax = charTo;\n\n        // Specify the area inside page margins\n        STRUCT_RECT rc = default(STRUCT_RECT);\n        rc.top = HundredthInchToTwips(e.MarginBounds.Top);\n        rc.bottom = HundredthInchToTwips(e.MarginBounds.Bottom);\n        rc.left = HundredthInchToTwips(e.MarginBounds.Left);\n        rc.right = HundredthInchToTwips(e.MarginBounds.Right);\n\n        // Specify the page area\n        STRUCT_RECT rcPage = default(STRUCT_RECT);\n        rcPage.top = HundredthInchToTwips(e.PageBounds.Top);\n        rcPage.bottom = HundredthInchToTwips(e.PageBounds.Bottom);\n        rcPage.left = HundredthInchToTwips(e.PageBounds.Left);\n        rcPage.right = HundredthInchToTwips(e.PageBounds.Right);\n\n        // Get device context of output device\n        IntPtr hdc = default(IntPtr);\n        hdc = e.Graphics.GetHdc();\n\n        // Fill in the FORMATRANGE structure\n        STRUCT_FORMATRANGE fr = default(STRUCT_FORMATRANGE);\n        fr.chrg = cr;\n        fr.hdc = hdc;\n        fr.hdcTarget = hdc;\n        fr.rc = rc;\n        fr.rcPage = rcPage;\n\n        // Non-Zero wParam means render, Zero means measure\n        Int32 wParam = default(Int32);\n        if (measureOnly)\n        {\n            wParam = 0;\n        }\n        else\n        {\n            wParam = 1;\n        }\n\n        // Allocate memory for the FORMATRANGE struct and\n        // copy the contents of our struct to this memory\n        IntPtr lParam = default(IntPtr);\n        lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fr));\n        Marshal.StructureToPtr(fr, lParam, false);\n\n        // Send the actual Win32 message\n        int res = 0;\n        res = SendMessage(Handle, EM_FORMATRANGE, wParam, lParam);\n\n        // Free allocated memory\n        Marshal.FreeCoTaskMem(lParam);\n\n        // and release the device context\n        e.Graphics.ReleaseHdc(hdc);\n\n        return res;\n    }\n\n    /// <summary>\n    /// Convert between 1/100 inch (unit used by the .NET framework)\n    /// and twips (1/1440 inch, used by Win32 API calls)\n    /// </summary>\n    /// <param name="n">Value in 1/100 inch</param>\n    /// <returns>Value in twips</returns>\n    private Int32 HundredthInchToTwips(int n)\n    {\n        return Convert.ToInt32(n * 14.4);\n    }\n\n    /// <summary>\n    /// Free cached data from rich edit control after printing\n    /// </summary>\n    public void FormatRangeDone()\n    {\n        IntPtr lParam = new IntPtr(0);\n        SendMessage(Handle, EM_FORMATRANGE, 0, lParam);\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

使用示例:

\n
private void printDocument1_BeginPrint(object sender, System.Drawing.Printing.PrintEventArgs e)\n{\n    // Start at the beginning of the text\n    firstCharOnPage = 0;\n}\n\nprivate void printDocument1_EndPrint(object sender, System.Drawing.Printing.PrintEventArgs e)\n{\n    // Clean up cached information\n    richTextBoxEx1.FormatRangeDone();\n}\n\nprivate void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)\n{\n    firstCharOnPage = richTextBoxEx1.FormatRange(false, e, firstCharOnPage, richTextBoxEx1.TextLength);\n    // check if there are more pages to print\n    if (firstCharOnPage < richTextBoxEx1.TextLength)\n        e.HasMorePages = true;\n    else\n        e.HasMorePages = false;\n}\n\nprivate void printToolStripButton_Click(object sender, EventArgs e)\n{\n    //Print the contents here\n    printDocument1.Print();\n}\n
Run Code Online (Sandbox Code Playgroud)\n