开发者

how to print Rich text box contents on any device contenxt with proper formatting?

i would like to print the rich text box contents with formatting to any device context, for example I would li开发者_运维技巧ke to print on panel or any other control which is associated to actual print device.

I am simulating print preview using panel by drawing some contents from a custom designed form, rich text content is one among the content of that form

is there any best solution to address this??


below is code that prints an rtf control's contents to the printer. i could be adapted to print to any old dc fairly easy. the language is powerbasic, but it could be easily translated in to C, pascal or whatever:

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


I have used the below extended control to achieve my RTF printing.

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

        }
    }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜