richTextBox.DrawToBitmap Does Not Draw Containing Text?

后端 未结 6 1368
盖世英雄少女心
盖世英雄少女心 2021-01-15 14:34

If I have a richTextBox and run DrawToBitmap on it, it doesn\'t draw any of the text inside of the richTextBox.

Bitmap b = new Bitmap(rtb.Width, rtb.Height         


        
相关标签:
6条回答
  • 2021-01-15 14:59

    I tested the methods above, and whenever I load the saved Bitmap into an ImageViewer(Like Paint), it would have the SaveFileDialog-UI faded into the background of the text. Luckily, I found an easy fix:

    SaveFileDialog bfsd = new SaveFileDialog();       
    var rtb = richTextBox1;
    
            bfsd.Filter = "Bitmap (*.bmp)|*.bmp|All Files (*.*)|*.*";
            bfsd.Title = "Save your text as a Bitmap File";
    
            rtb.Update(); // Ensure RTB fully painted
            Bitmap bmp = new Bitmap(rtb.Width, rtb.Height);
            using (Graphics gr = Graphics.FromImage(bmp))
            {
                gr.CopyFromScreen(rtb.PointToScreen(Point.Empty), Point.Empty, rtb.Size);
            }
    
            if (bfsd.ShowDialog()==DialogResult.OK)
            {
             Draw:
                try
                {
                    bmp.Save(bfsd.FileName);
    
                    bmp.Dispose();
                }
                catch (Exception)
                {
                    DialogResult dr = MessageBox.Show("An error ocurred while attempting to save your Image...", "Error! Error!", MessageBoxButtons.RetryCancel, MessageBoxIcon.Error);
    
                    if (dr == DialogResult.Retry)
                    {
                        goto Draw;
                    }
                    else if (dr == DialogResult.Cancel)
                    {
                        return;
                    }
                }
    
    • That way, it paints the picture before you even press Save(Don't worry, it won't actually save the image until you press Save)

    Pressing Cancel doesn't effect the process, because when you press the Button or MenuStripItem to save it, it will update & re-paint it :)

    I implemented a try-catch method, so that it will catch an error if one occurs, rather than the app just (Not Responding)

    The catch method is a Retry Button

    It will catch the error, and give you the choice to either Cancel the whole Operation, or Retry

    I used a goto to be able to just rewind, and make another attempt to save the file, rather than having the SaveFileDialog appear again.

    I hope this helps you :)

    0 讨论(0)
  • 2021-01-15 15:01

    I know this is relatively old, but a working solution that I found at http://www.windows-tech.info/3/8ffaf21eed5de2d4.php:

    public static Bitmap RtbToBitmap(RichTextBox rtb)
    {
        rtb.Update(); // Ensure RTB fully painted
        Bitmap bmp = new Bitmap(rtb.Width, rtb.Height);
        using (Graphics gr = Graphics.FromImage(bmp))
        {
            gr.CopyFromScreen(rtb.PointToScreen(Point.Empty), Point.Empty, rtb.Size);
        }
        return bmp;
    }
    
    0 讨论(0)
  • 2021-01-15 15:17

    I found a related answer here: how to print Rich text box contents on any device contenxt with proper formatting?

    I changed this to render my off screen RichTextBox to a bitmap. This way I could create a bitmap off screen and then send it to OpenGL.

        // 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);
    
        /// <summary>
        /// Render the specified RichTextBox onto the specified bitmap
        /// </summary>
        /// <param name="textBox">RichTextBox to render</param>
        /// <param name="bitmap">Bitmap to render the RichTextBox onto</param>
        public void RenderToBitmap(RichTextBox textBox, Bitmap bitmap)
        {
            // Set area to render to be entire bitmap
            RECT rect;
            rect.Left   = 0;
            rect.Top    = 0;
            rect.Right  = (int)(bitmap.Width  * anInch);
            rect.Bottom = (int)(bitmap.Height * anInch);
    
            Graphics g   = Graphics.FromImage(bitmap);
            IntPtr   hdc = g.GetHdc();
    
            FORMATRANGE fmtRange;
            fmtRange.chrg.cpMin = textBox.GetCharIndexFromPosition(new Point(0,0));
            fmtRange.chrg.cpMax = textBox.GetCharIndexFromPosition(new Point(bitmap.Width,bitmap.Height));
            fmtRange.hdc        = hdc;                  // Use the same DC for measuring and rendering
            fmtRange.hdcTarget  = hdc;
            fmtRange.rc         = rect;
            fmtRange.rcPage     = rect;
    
            IntPtr lparam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fmtRange));
            Marshal.StructureToPtr(fmtRange, lparam, false);
    
            // Render the control to the bitmap
            SendMessage(textBox.Handle, EM_FORMATRANGE, new IntPtr(1), lparam);
    
            // Clean up
            Marshal.FreeCoTaskMem(lparam);
            g.ReleaseHdc(hdc);
        }
    
    0 讨论(0)
  • 2021-01-15 15:21

    This thread came up second in Google. Seems to have exactly what you want. Because I imagine you're using this inside your function from this question Accepting Form Elements As Method Arguments?, it's probably best to do something like this.

    if(inputControl is RichTextBox)
    {
        //do specifc magic here
    }
    else
    {
        //general case
    }
    

    You can check for a Control containing RichTextBox recursively

    bool ContainsOrIsRichTextBox(Control inputControl)
    {
        if(inputControl is RichTextBox) return true;
        foreach(Control control in inputControl.Controls)
        {
            if(ContainsOrIsRichTextBox(control)) return true;
        }
        return false;
    }
    

    I haven't compiled this, and there's a way of doing it without risking a StackOverflowException, but this should get you started.

    0 讨论(0)
  • 2021-01-15 15:21

    For what it's worth, the later version of the RichTextBox control supports the DrawToBitmap method properly; it also improves performance and has more features.

    internal class RichTextBox5: RichTextBox
    {
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        static extern IntPtr LoadLibrary(string lpFileName);
    
        protected override CreateParams CreateParams
        {
            get
            {
               CreateParams cparams = base.CreateParams; 
               if (LoadLibrary("msftedit.dll") != IntPtr.Zero)
               {
                  cparams.ClassName = "RICHEDIT50W";
               }
               return cparams;
             }
        }
    }
    
    0 讨论(0)
  • 2021-01-15 15:23

    From the MSDN Library article for RichTextBox.DrawToBitmap():

    This method is not relevant for this class.

    A crummy way to say that the native Windows richedit control doesn't support WM_PRINT. Taking a screen shot is an option, Novikov gave you a link to my answer.

    0 讨论(0)
提交回复
热议问题