[DllImport("gdi32.dll", CharSet = CharSet.Auto)]
static extern bool TextOut(IntPtr hdc, int nXStart, int nYStart,
string lpString, int cbString); (Please see note for CharSet in tips)
<DllImport("gdi32")> _
Shared Function TextOut(ByVal hdc As IntPtr, ByVal x As Integer, _
ByVal y As Integer, ByVal textstring As String, _
ByVal charCount As Integer) As Boolean
End Function
TextOut, unlike the Text property, have to be called every time Windows asks for a control to repaint. By using the Graphics.CopyFromScreen method one can copy the output of a Textout command and use that for repainting.
Unlike graphics.drawstring, Textout can work with fonts other than True Type, Open Type, and PostScript fonts. If you have a font that's supported by Windows but not .net you can most likely use this command to draw it.
[CharSet = CharSet.Auto] According to my experience this parameter should be used when using a LOGFONT structure and the CreateFontIndirect fuction, otherwise the selected font will not be displayed. All flags will be done (lfItalic, lfUnderline ...) but not the lfFaceName string.
// Paste this at the beginning of your file if not present:
using System.Drawing;
using System.Runtime.InteropServices;
//Create a class that subclass Control and paste these methods into it.
//Then place the new control on a form.
DllImport("gdi32.dll")]
static extern bool TextOut(IntPtr hdc, int nXStart, int nYStart,
string lpString, int cbString);
[DllImport("gdi32.dll")]
static extern bool GetTextExtentPoint(IntPtr hdc, string lpString,
int cbString, ref Size lpSize);
[DllImport("gdi32.dll")]
public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
[DllImport("GDI32.dll")]
public static extern bool DeleteObject(IntPtr objectHandle);
#region Font
protected override void OnKeyPress(KeyPressEventArgs e)
{
Text += e.KeyChar.ToString();
//Note, painting should not be done in the OnKeyPress method, instead:
Refresh();
//You may want to meassure the string's size for layout purposes.
using(Graphic g = base.createGraphics())
{
//Do the GetHdc(), GetTextExtentPoint, etc, here. Remember that you have
//to delete related objects such as fonts and call ReleaseHdc on graphics
//afterwards. If you for some reason don't want to do this you can use a
//SafeHandle (needs to be subclassed) which does this for you.
//Remember to use HandleRef when appropriate. For instance if you create
//a color that you set through SelectObject the .net garbage collector will
//happily delete the color unless you refere to it after the drawing call or
//use a HandleRef.
//In this example we used the base class font and therefore need not worry
//about the GC deleting the Font in mid drawing.
//Also keep in mind that all graphics objects _you_ create must be disposed,
//which is done through the using clause in this example. It can also be done
//by calling g.Dispose() in a finally clause (to guarantee that it's executed)
}
}
protected override void OnPaint(PaintEventArgs e)
{
IntPtr HDC = e.Graphics.GetHdc();
//We have to use SelectObject to set the font, color and other properties.
IntPtr last_font = SelectObject(HDC, Font.ToHfont());
Size MeasureSize = new Size(0, 0);
int y_pos = 0;
int x_pos = 2;
//Tasks such as these should not be done in the drawing loop as they
//slow down the drawing.
String[] lines = Text.split(new char[] { '\n' });
try
{
//We draw out each line of text.
for(int c=0; c < lines.Length; c++)
{
String line = lines[c];
TextOut(HDC, x_pos, y_pos, line, line.Length);
//Unless you change the font, the line height never
//changes so measuring the text at each draw call is
//inefficient. Also it measure empty lines at 0 height
//so pressing multiple enters will not move the text down.
GetTextExtentPoint(HDC, line, line.Length, ref MeasureSize);
y += MeasureSize.Height;
//You can use the MeasureSize.Width property to implement
//word wrapping.
}
}
finally
{
//Put here to make sure we don't get a memory leak.
DeleteObject(SelectObject(HDC, last_font));
e.Graphics.ReleaseHdc(HDC);
//Don't call dispose() on the Graphics object unless you createded it.
}
}
Graphics.DrawString
Graphics.MeasureString
Graphics.MeasureCharacterRanges