打印RichTextBox的 - 总是在同一个页面 [英] Printing RichTextBox - always the same page

查看:149
本文介绍了打印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?

推荐答案

您可以通过发送的 RuchTextBox 内容=https://msdn.microsoft.com/en-us/library/windows/desktop/bb788020(v=vs.85).aspx相对=nofollow> EM_FORMATRANGE 消息吧。

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

此消息通常用于丰富的编辑
控制的用于输出设备的内容格式化诸如打印机。

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 EndPrint 下面的代码来执行打印的PrintDocument 的事件和使用。

  • 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.

下面是一个什么样上述我的完整的工作代码。

Here is the complete working code of what I described above.

RichTextBoxEx支持打印:

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