richTextBox.DrawToBitmap не рисует содержащий текст?
Если у меня есть richTextBox и я запускаю DrawToBitmap, он не рисует текст внутри richTextBox.
Bitmap b = new Bitmap(rtb.Width, rtb.Height);
inputControl.DrawToBitmap(b, new Rectangle(0, 0, b.Width, b.Height));
Есть ли способ это исправить?
5 ответов
Эта тема заняла второе место в 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;
}
Я не скомпилировал это, и есть способ сделать это, не рискуя StackruException, но это должно помочь вам начать.
Я знаю, что это относительно старое, но рабочее решение, которое я нашел по адресу 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;
}
Из статьи библиотеки MSDN для RichTextBox.DrawToBitmap():
Этот метод не подходит для этого класса.
Неприличный способ сказать, что родной элемент управления Windows richedit не поддерживает WM_PRINT. Взять снимок экрана - вариант, Новиков дал вам ссылку на мой ответ.
Более того, более поздняя версия элемента управления 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;
}
}
}
Я нашел связанный ответ здесь: как напечатать содержимое текстового поля на любом устройстве с правильным форматированием?
Я изменил это, чтобы сделать мой закадровый 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);
}
Я протестировал вышеперечисленные методы, и всякий раз, когда я загружаю сохраненное растровое изображение в ImageViewer(например, Paint), пользовательский интерфейс SaveFileDialog переходил в фон текста. К счастью, я нашел простое решение:
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
(Не волнуйтесь, изображение не сохранится, пока вы не нажметеSave
)
Нажатие Cancel
не влияет на процесс, потому что при нажатии Button
или MenuStripItem
чтобы сохранить, он обновит и перекрасит:)
Я реализовал try
-catch
метод, чтобы он перехватил ошибку, если она возникнет, а не приложение просто (Not Responding)
В catch
метод - это Retry
Button
Он обнаружит ошибку и предоставит вам выбор: Cancel
целый Operation
, или Retry
Я использовал goto
чтобы иметь возможность просто перемотать назад и сделать еще одну попытку сохранить файл, вместо того, чтобы SaveFileDialog
снова появиться.
Я надеюсь, это поможет вам:)