打印RichTextBox [英] Printing RichTextBox

查看:62
本文介绍了打印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 Printer创建一个新页面?

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

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

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

推荐答案

您可以通过发送打印 RuchTextBox 的内容= https://msdn.microsoft.com/zh-cn/library/windows/desktop/bb788020(v=vs.85).aspx rel = nofollow noreferrer> EM_FORMATRANGE 消息发送给它。

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


此消息通常用于为打印机等输出设备格式化格式丰富的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:


  • 首先创建一个 RichtextBoxEx 类,该类继承自 RichTextBox 并实现 FormatRange 方法,它的工作是打印控件内容的每一页。完整的代码在下面列出。

  • 然后创建一个表单并放置一个 RichTextBoxEx PrintDocument 并处理 BeginPrint PrintPage PrintDocument 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.

创建 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文章 MartinMüller撰写的.NET RichTextBox的所见即所得打印结果

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天全站免登陆