问题
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 pressSave)
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