如何使用正确的格式在任何设备上下文中打印富文本框内容?

时间:2010-03-03 03:07:03

标签: printing rtf

我想将格式框内容与格式打印到任何设备上下文,例如我想在面板上打印或与实际打印设备关联的任何其他控件。

我通过从自定义设计的表单中绘制一些内容来使用面板模拟打印预览,富文本内容是该表单的内容之一

有没有解决这个问题的最佳解决方案?

3 个答案:

答案 0 :(得分:0)

下面是将rtf控件的内容打印到打印机的代码。我可以很容易地适应任何旧的直流印刷。语言是强大的,但可以很容易地翻译成C语言,pascal语言或其他语言:

SUB PrintRichTextBox (  hWnd as LONG, hInst as LONG, rtfEdit as LONG, LM as Single, _
                        RM as Single, TM as Single, BM as Single )
   '
   '  Purpose:
   '           Prints the contents of an RTF text box given it's handle, the
   '           calling program's handle(s), and the page margins.
   '
   '  Parameters:
   '           hWnd     = Parent window (used for print common dlg)
   '           hInst    = Instance of calling program
   '           rtfEdit  = Handle of rich edit control
   '           LM       = Left Margin in inches
   '           RM       = Right Margin in inches
   '           TM       = Top Margin in inches
   '           BM       = Bottom Margin in inches
   '
   Dim fr as FORMATRANGE
   Dim rDocInfo as DOCINFO
   Dim iTextOut as LONG
   Dim iTextAmt as LONG
   Dim pd as PRINTDLGAPI
   Dim zString as ASCIIZ * 200
   Dim iWidthTwips&
   Dim iHeightTwips&

   '- Setup the print common dialog
   pd.lStructSize = len(pd)
   pd.hwndOwner = hWnd
   pd.hDevMode = %NULL
   pd.hDevNames = %NULL
   pd.nFromPage = 0
   pd.nToPage = 0
   pd.nMinPage = 0
   pd.nMaxPage = 0
   pd.nCopies = 0
   pd.hInstance = hInst
   pd.Flags = %PD_RETURNDC or %PD_NOPAGENUMS or %PD_PRINTSETUP
   pd.lpfnSetupHook = %NULL
   pd.lpPrintSetupTemplateName = %NULL
   pd.lpfnPrintHook = %NULL
   pd.lpPrintTemplateName = %NULL

   if PrintDlg(pd) then

      SetCursor LoadCursor( %NULL, BYVAL %IDC_WAIT )

      '- Fill format range structure
      '
      '  NOTE:
      '     This gave me fits. I was looking at the book from
      '     Microsoft Press called Programming the Windows 95
      '     Iterface. It said (via example) that the
      '     Rectagle was defined in Pixels. This didn't work right.
      '     The SDK, however, said the measurements needed to be
      '     in Twips! This seems to work fine.
      '
      '
      fr.hdc = pd.hDC
      fr.hdcTarget = pd.hDC
      fr.chrg.cpMin = 0
      fr.chrg.cpMax = -1

      fr.rc.nTop = TM * 1440
      fr.rcPage.nTop = fr.rc.nTop

      fr.rc.nLeft = LM * 1440
      fr.rcPage.nLeft = fr.rc.nLeft

      '- Get page dimensions in Twips
      iWidthTwips& = int((GetDeviceCaps(pd.hDC, %HORZRES) / GetDeviceCaps(pd.hDC, %LOGPIXELSX)) * 1440)
      iHeightTwips& = int((GetDeviceCaps(pd.hDC, %VERTRES) / GetDeviceCaps(pd.hDC, %LOGPIXELSY)) * 1440)

      fr.rc.nRight = iWidthTwips& - RM * 1440
      fr.rcPage.nRight = fr.rc.nRight

      fr.rc.nBottom = iHeightTwips& - BM * 1440
      fr.rcPage.nBottom = fr.rc.nBottom

      '- Fill rDocInfo structure
      rDocInfo.cbSize = len(rDocInfo)
      zString = "RTF Printer"
      rDocInfo.lpszDocName = VARPTR(zString)
      rDocInfo.lpszOutput = %NULL

      '- Here we go
      StartDoc pd.hDC, rDocInfo
      StartPage pd.hDC

      '- This does the printing. We send messages
      '  to the edit box telling it to format it's
      '  text to fit the Printer's DC.
      '
      iTextOut = 0
      iTextAmt = SendMessage(rtfEdit, %WM_GETTEXTLENGTH, 0, 0)

      do while iTextOut < iTextAmt

         iTextOut = SendMessage(rtfEdit, %EM_FORMATRANGE, _
                     1, VARPTR(fr))

         if iTextOut < iTextAmt then
            EndPage pd.hDC
            StartPage pd.hDC
            fr.chrg.cpMin = iTextOut
            fr.chrg.cpMax = -1
         end if

      loop

      SendMessage rtfEdit, %EM_FORMATRANGE, 1, %NULL

      '- Finish the printing.
      EndPage pd.hDC
      EndDoc pd.hDC

      DeleteDC pd.hDC
      SetCursor LoadCursor( %NULL, BYVAL %IDC_ARROW )

   else
      ' MsgBox "Canceled !"
   end if


END SUB

答案 1 :(得分:0)

Raymond Chen在他的博客上谈到了这个问题 How do I print the contents of a rich text control?

答案 2 :(得分:0)

我使用下面的扩展控件来实现我的RTF打印。

    using System;
    using System.Windows.Forms;
    using System.Drawing;
    using System.Runtime.InteropServices;
    using System.Drawing.Printing;

    namespace RichTextBoxPrintCtrl
    {
        public class RichTextBoxPrintCtrl : RichTextBox
        {
            //Convert the unit used by the .NET framework (1/100 inch) 
            //and the unit used by Win32 API calls (twips 1/1440 inch)
            private const double anInch = 14.4;

            [StructLayout(LayoutKind.Sequential)]
            private struct RECT
            {
                public int Left;
                public int Top;
                public int Right;
                public int Bottom;
            }

            [StructLayout(LayoutKind.Sequential)]
            private struct CHARRANGE
            {
                public int cpMin;         //First character of range (0 for start of doc)
                public int cpMax;           //Last character of range (-1 for end of doc)
            }

            [StructLayout(LayoutKind.Sequential)]
            private struct FORMATRANGE
            {
                public IntPtr hdc;             //Actual DC to draw on
                public IntPtr hdcTarget;       //Target DC for determining text formatting
                public RECT rc;                //Region of the DC to draw to (in twips)
                public RECT rcPage;            //Region of the whole DC (page size) (in twips)
                public CHARRANGE chrg;         //Range of text to draw (see earlier declaration)
            }

            private const int WM_USER = 0x0400;
            private const int EM_FORMATRANGE = WM_USER + 57;

            [DllImport("USER32.dll")]
            private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);

            // Render the contents of the RichTextBox for printing
            //  Return the last character printed + 1 (printing start from this point for next page)
            public int Print(int charFrom, int charTo, PrintPageEventArgs e)
            {
                //Calculate the area to render and print
                RECT rectToPrint;
                rectToPrint.Top = (int)(e.MarginBounds.Top * anInch);
                rectToPrint.Bottom = (int)(e.MarginBounds.Bottom * anInch);
                rectToPrint.Left = (int)(e.MarginBounds.Left * anInch);
                rectToPrint.Right = (int)(e.MarginBounds.Right * anInch);

                //Calculate the size of the page
                RECT rectPage;
                rectPage.Top = (int)(e.PageBounds.Top * anInch);
                rectPage.Bottom = (int)(e.PageBounds.Bottom * anInch);
                rectPage.Left = (int)(e.PageBounds.Left * anInch);
                rectPage.Right = (int)(e.PageBounds.Right * anInch);

                IntPtr hdc = e.Graphics.GetHdc();

                FORMATRANGE fmtRange;
                fmtRange.chrg.cpMax = charTo;               //Indicate character from to character to 
                fmtRange.chrg.cpMin = charFrom;
                fmtRange.hdc = hdc;                    //Use the same DC for measuring and rendering
                fmtRange.hdcTarget = hdc;              //Point at printer hDC
                fmtRange.rc = rectToPrint;             //Indicate the area on page to print
                fmtRange.rcPage = rectPage;            //Indicate size of page

                IntPtr res = IntPtr.Zero;

                IntPtr wparam = IntPtr.Zero;
                wparam = new IntPtr(1);

                //Get the pointer to the FORMATRANGE structure in memory
                IntPtr lparam = IntPtr.Zero;
                lparam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fmtRange));
                Marshal.StructureToPtr(fmtRange, lparam, false);

                //Send the rendered data for printing 
                res = SendMessage(Handle, EM_FORMATRANGE, wparam, lparam);

                //Free the block of memory allocated
                Marshal.FreeCoTaskMem(lparam);

                //Release the device context handle obtained by a previous call
                e.Graphics.ReleaseHdc(hdc);

                //Return last + 1 character printer
                return res.ToInt32();
            }

        }
    }