richTextBox.DrawToBitmap 不绘制包含文本?

发布于 2024-10-16 23:05:37 字数 237 浏览 1 评论 0原文

如果我有一个 richTextBox 并在其上运行 DrawToBitmap,它不会绘制 richTextBox 内的任何文本。

Bitmap b = new Bitmap(rtb.Width, rtb.Height);
inputControl.DrawToBitmap(b, new Rectangle(0, 0, b.Width, b.Height));

有什么办法可以解决这个问题吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

爱的十字路口 2024-10-23 23:05:37

我知道这是相对较旧的,但我在 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;
}

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;
}
嘿哥们儿 2024-10-23 23:05:37

此帖子 在 Google 中排名第二。似乎正是您想要的。因为我想您在这个问题的函数中使用它 接受表单元素作为方法参数?,最好这样做。

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

您可以递归地检查包含 RichTextBox 的控件,

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

我还没有编译它,并且有一种方法可以在不冒 StackOverflowException 风险的情况下执行此操作,但这应该可以帮助您入门。

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.

献世佛 2024-10-23 23:05:37

来自 RichTextBox.DrawToBitmap() 的 MSDN 库文章:

此方法与此类无关。

一种糟糕的说法是本机 Windows richedit 控件不支持 WM_PRINT。可以选择截屏,诺维科夫为您提供了我的答案的链接。

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.

半步萧音过轻尘 2024-10-23 23:05:37

值得一提的是,RichTextBox 控件的更高版本可以正确支持 DrawToBitmap 方法;它还提高了性能并具有更多功能。

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

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;
         }
    }
}
涫野音 2024-10-23 23:05:37

我在这里找到了相关的答案:如何以正确的格式在任何设备环境上打印富文本框内容?

我更改了此设置以将屏幕外的 RichTextBox 渲染为位图。这样我就可以在屏幕外创建一个位图,然后将其发送到 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);
    }

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);
    }
梦行七里 2024-10-23 23:05:37

我测试了上面的方法,每当我将保存的位图加载到 ImageViewer(如 Paint)中时,它都会使 SaveFileDialog-UI 淡入文本的背景中。幸运的是,我找到了一个简单的解决方法:

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;
                }
            }
  • 这样,它会在您按下 Save 之前绘制图片(别担心,在您按下 之前它不会真正保存图像保存

取消不会影响该过程,因为当您按ButtonMenuStripItem进行保存时它,它将更新&重新绘制它:)

我实现了一个 try-catch 方法,这样如果发生错误,它就会捕获错误,而不是应用程序只是 (Not Responding )

catch 方法是一个 Retry Button

它将捕获错误,并让您选择 Cancel 整个操作,或重试

我使用了goto 来倒带,并再次尝试保存文件,而不是让 SaveFileDialog 再次出现。

我希望这对你有帮助:)

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 :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文