打印 RichTextBox [英] Printing RichTextBox

查看:20
本文介绍了打印 RichTextBox的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am making a simple WinForms App and I wanted to allow the user to print the Text from RichTextBox.

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

I followed MSDN link then.. And it works for a real printer (by real I mean that one I can touch:) )

但是如果我想使用某种 PDF 打印机怎么办?然后我必须说它在只打印一页时有效.每个下一页都打印在同一第一页,这意味着文本被叠印.这很明显,但我能做些什么来强制 PDF 打印机创建一个新页面?

But what if I want use some kind of PDF Printer? Then I must say it works when only one page is printed. Every next page is being printed on the same, first page, which means the text is being overprinted. This is obvious, but what I can do do force PDF Printer to create a new Page?

这是我的代码:

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();
        }

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

What should I do to print every next page in a proper way?

推荐答案

您可以通过发送 EM_FORMATRANGE 消息给它.

You can print the content of your RuchTextBox by sending a EM_FORMATRANGE message to it.

此消息通常用于格式化 Rich Edit 的内容控制打印机等输出设备.

This message is typically used to format the content of rich edit control for an output device such as a printer.

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

To implement this solution, you can do these steps:

  • 首先创建一个继承自 RichTextBoxRichtextBoxEx 类,并实现一个 FormatRange 方法,它的工作是打印控件内容的每一页.下面列出了完整的代码.
  • 然后创建一个Form并在其上放置一个RichTextBoxEx,PrintDocument并处理BeginPrint,PrintDocument 的 PrintPage 和 EndPrint 事件,并使用以下代码进行打印.
  • First create a RichtextBoxEx class that inherits from RichTextBox and implement a FormatRange method that its job is to print each page of your control contents. The complete code is listed below.
  • Then Create a Form and put a RichTextBoxEx, PrintDocument on it and handle BeginPrint, PrintPage and EndPrint events of PrintDocument and use following codes to perform print.

请注意

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

  1. Using this way, you can print the content of your control with all of formatting applied to text, that is better than printing all text in a black color with one font and size. Also you can set the font and size of content to be in one font and size and color.

Creating RichtextBoxEx 只是为了封装,完全是可选的,如果你想使用你现有的控件,你可以使用我的 FormatRange 方法的内容下面提供并将您的控件的属性传递给它以执行打印.

Creating RichtextBoxEx is just for encapsulation and is completely optional and if you want to use your existing control, simply you can use content of FormatRange method that I provided below and pass properties of your control to it to perform print.

支持打印的 RichTextBoxEx:

这是我上面描述的完整工作代码.该代码摘自 msdn 文章 从 Martin Müller 的文章中获取所见即所得的打印结果.

Here is the complete working code of what I described above. The code is extracted from the msdn article Getting WYSIWYG Print Results from a .NET RichTextBox article by 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();
}

这篇关于打印 RichTextBox的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆