richTextBox.DrawToBitmap Does Not Draw Containing Text?

跟風遠走 提交于 2019-12-30 11:17:15

问题


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);
inputControl.DrawToBitmap(b, new Rectangle(0, 0, b.Width, b.Height));

Is there any way to fix this?


回答1:


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.




回答2:


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



回答3:


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.




回答4:


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



回答5:


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



回答6:


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)
        {
            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)
                {
                    drawToBitmapbmpToolStripMenuItem_Click(sender, e);
                }
                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 hope this helps you :)



来源:https://stackoverflow.com/questions/4974276/richtextbox-drawtobitmap-does-not-draw-containing-text

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!