この記事で紹介している方法では、横幅ぴったりに文字を表示するため、アルファベットの単語の途中でワードラップの分割が発生します。
英単語の途中で極力分割をしないワードラップのロジックについてはこちらの記事を参照してください。
GetTextExtentExPoint()
関数を利用します。using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace DrawStringWordWrap
{
public partial class FormWordWrapCalcDraw : Form
{
public enum BkMode
{
TRANSPARENT = 1,
OPAQUE = 2
}
[Flags]
public enum ETOOptions : uint
{
ETO_CLIPPED = 0x4,
ETO_GLYPH_INDEX = 0x10,
ETO_IGNORELANGUAGE = 0x1000,
ETO_NUMERICSLATIN = 0x800,
ETO_NUMERICSLOCAL = 0x400,
ETO_OPAQUE = 0x2,
ETO_PDY = 0x2000,
ETO_RTLREADING = 0x800,
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int _Left;
public int _Top;
public int _Right;
public int _Bottom;
}
[StructLayout(LayoutKind.Sequential)]
public struct SIZE
{
public int cx;
public int cy;
public SIZE(int cx, int cy)
{
this.cx = cx;
this.cy = cy;
}
}
[DllImport("gdi32.dll")]
public static extern int SetBkMode(IntPtr hdc, int iBkMode);
[DllImport("gdi32.dll")]
public static extern uint SetTextColor(IntPtr hdc, int crColor);
[DllImport("gdi32.dll", EntryPoint = "SelectObject")]
public static extern IntPtr SelectObject([In] IntPtr hdc, [In] IntPtr hgdiobj);
[DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DeleteObject([In] IntPtr hObject);
[DllImport("gdi32.dll", EntryPoint = "GetTextExtentExPointW")]
static extern bool GetTextExtentExPoint(IntPtr hdc, [MarshalAs(UnmanagedType.LPWStr)] string lpszStr,
int cchString, int nMaxExtent, out int lpnFit, int[] alpDx, out SIZE lpSize);
[DllImport("gdi32.dll", EntryPoint = "ExtTextOutW")]
public static extern bool ExtTextOut(IntPtr hdc, int X, int Y, uint fuOptions,
[In] ref RECT lprc, [MarshalAs(UnmanagedType.LPWStr)] string lpString, uint cbCount, [In] IntPtr lpDx);
public FormWordWrapCalcDraw()
{
InitializeComponent();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
int areaLeft = 128;
int areaTop = 32;
int areaWidth = 128;
int areaHeight = 160;
Pen p = new Pen(Color.FromArgb(0x45, 0x72, 0xAA));
Rectangle r = new Rectangle(areaLeft, areaTop, areaWidth, areaHeight);
e.Graphics.DrawRectangle(p, r);
Font f = new Font("Yu Gothic UI", 14);
string DocText = "ぺんぎんクッキー(Penguin Cookie)を食べれば、みんなHappy Time!!";
IntPtr hDC = e.Graphics.GetHdc();
SetTextColor(hDC, ColorTranslator.ToWin32(Color.Black));
IntPtr oldfnt = SelectObject(hDC, f.ToHfont());
int[] Dx = new int[DocText.Length];
int FitCount;
SIZE sz;
GetTextExtentExPoint(hDC, DocText, DocText.Length, 1024, out FitCount, Dx, out sz);
for (int i = 0; i < Dx.Length; i++) {
textBox1.Text += string.Format("{0:d}\r\n",Dx[i]);
}
int idx = 0;
int startidx = 0;
int startpos = 0;
int posx = areaLeft;
int posy = areaTop;
RECT rect = new RECT() { _Left=areaLeft, _Top=areaTop, _Right=areaLeft+areaHeight, _Bottom= areaTop+areaHeight};
SetBkMode(hDC, (int)BkMode.TRANSPARENT);
while (idx < Dx.Length-1) {
if (areaWidth < Dx[idx + 1] - startpos) {
string drawText = DocText.Substring(startidx, idx - startidx+1);
ExtTextOut(hDC, posx, posy, (uint)ETOOptions.ETO_CLIPPED, ref rect, drawText, (uint)drawText.Length, IntPtr.Zero);
posy += sz.cy;
startidx = idx+1;
startpos = Dx[idx];
}
idx++;
}
string lastdrawText = DocText.Substring(startidx);
ExtTextOut(hDC, posx, posy, (uint)ETOOptions.ETO_CLIPPED, ref rect, lastdrawText, (uint)lastdrawText.Length, IntPtr.Zero);
IntPtr cfont = SelectObject(hDC, oldfnt);
DeleteObject(cfont);
e.Graphics.ReleaseHdc();
}
}
}
int areaLeft = 128;
int areaTop = 32;
int areaWidth = 128;
int areaHeight = 160;
Pen p = new Pen(Color.FromArgb(0x45, 0x72, 0xAA));
Rectangle r = new Rectangle(areaLeft, areaTop, areaWidth, areaHeight);
e.Graphics.DrawRectangle(p, r);
Font f = new Font("Yu Gothic UI", 14);
string DocText = "ぺんぎんクッキー(Penguin Cookie)を食べれば、みんなHappy Time!!";
IntPtr hDC = e.Graphics.GetHdc();
SetTextColor(hDC, ColorTranslator.ToWin32(Color.Black));
IntPtr oldfnt = SelectObject(hDC, f.ToHfont());
Dx
配列に設定されます。 int[] Dx = new int[DocText.Length];
int FitCount;
SIZE sz;
GetTextExtentExPoint(hDC, DocText, DocText.Length, 1024, out FitCount, Dx, out sz);
for (int i = 0; i < Dx.Length; i++) {
textBox1.Text += string.Format("{0:d}\r\n",Dx[i]);
}
int idx = 0;
int startidx = 0;
int startpos = 0;
int posx = areaLeft;
int posy = areaTop;
RECT rect = new RECT() { _Left=areaLeft, _Top=areaTop, _Right=areaLeft+areaHeight, _Bottom= areaTop+areaHeight};
SetBkMode(hDC, (int)BkMode.TRANSPARENT);
sz
変数のcyに設定されていますので、描画位置のY座標にsz.cy
の値を加算します。 while (idx < Dx.Length-1) {
if (areaWidth < Dx[idx + 1] - startpos) {
string drawText = DocText.Substring(startidx, idx - startidx+1);
ExtTextOut(hDC, posx, posy, (uint)ETOOptions.ETO_CLIPPED, ref rect, drawText, (uint)drawText.Length, IntPtr.Zero);
posy += sz.cy;
startidx = idx+1;
startpos = Dx[idx];
}
idx++;
}
string lastdrawText = DocText.Substring(startidx);
ExtTextOut(hDC, posx, posy, (uint)ETOOptions.ETO_CLIPPED, ref rect, lastdrawText, (uint)lastdrawText.Length, IntPtr.Zero);
IntPtr cfont = SelectObject(hDC, oldfnt);
DeleteObject(cfont);
e.Graphics.ReleaseHdc();
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace DrawStringWordWrap
{
public partial class FormWordWrapCalcDrawTextRenderer : Form
{
[StructLayout(LayoutKind.Sequential)]
public struct SIZE
{
public int cx;
public int cy;
public SIZE(int cx, int cy)
{
this.cx = cx;
this.cy = cy;
}
}
[DllImport("gdi32.dll", EntryPoint = "SelectObject")]
public static extern IntPtr SelectObject([In] IntPtr hdc, [In] IntPtr hgdiobj);
[DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DeleteObject([In] IntPtr hObject);
[DllImport("gdi32.dll", EntryPoint = "GetTextExtentExPointW")]
static extern bool GetTextExtentExPoint(IntPtr hdc, [MarshalAs(UnmanagedType.LPWStr)] string lpszStr,
int cchString, int nMaxExtent, out int lpnFit, int[] alpDx, out SIZE lpSize);
public FormWordWrapCalcDrawTextRenderer()
{
InitializeComponent();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
Font f = new Font("Yu Gothic UI", 14);
string DocText = "ぺんぎんクッキー(Penguin Cookie)を食べれば、みんなHappy Time!!";
int areaLeft = 128;
int areaTop = 32;
int areaWidth = 128;
int areaHeight = 160;
Pen p = new Pen(Color.FromArgb(0x45, 0x72, 0xAA));
Rectangle r = new Rectangle(areaLeft, areaTop, areaWidth, areaHeight);
e.Graphics.DrawRectangle(p, r);
int[] Dx = new int[DocText.Length];
int FitCount;
SIZE sz;
IntPtr hDC = e.Graphics.GetHdc();
IntPtr oldfnt = SelectObject(hDC, f.ToHfont());
GetTextExtentExPoint(hDC, DocText, DocText.Length, 1024, out FitCount, Dx, out sz);
IntPtr cfont = SelectObject(hDC, oldfnt);
DeleteObject(cfont);
e.Graphics.ReleaseHdc();
for (int i = 0; i < Dx.Length; i++) {
textBox1.Text += string.Format("{0:d}\r\n", Dx[i]);
}
int idx = 0;
int startidx = 0;
int startpos = 0;
int posx = areaLeft;
int posy = areaTop;
while (idx < Dx.Length - 1) {
if (areaWidth < Dx[idx + 1] - startpos) {
string drawText = DocText.Substring(startidx, idx - startidx + 1);
TextRenderer.DrawText(e.Graphics, drawText, f, new Rectangle(posx,posy,areaWidth,sz.cy),
Color.Black, TextFormatFlags.Default | TextFormatFlags.NoPadding);
posy += sz.cy;
startidx = idx + 1;
startpos = Dx[idx];
}
idx++;
}
string lastdrawText = DocText.Substring(startidx);
TextRenderer.DrawText(e.Graphics, lastdrawText, f, new Rectangle(posx, posy, areaWidth, sz.cy),
Color.Black, TextFormatFlags.Default | TextFormatFlags.NoPadding);
}
}
}
int areaLeft = 128;
int areaTop = 32;
int areaWidth = 128;
int areaHeight = 160;
Pen p = new Pen(Color.FromArgb(0x45, 0x72, 0xAA));
Rectangle r = new Rectangle(areaLeft, areaTop, areaWidth, areaHeight);
e.Graphics.DrawRectangle(p, r);
int[] Dx = new int[DocText.Length];
int FitCount;
SIZE sz;
IntPtr hDC = e.Graphics.GetHdc();
IntPtr oldfnt = SelectObject(hDC, f.ToHfont());
GetTextExtentExPoint(hDC, DocText, DocText.Length, 1024, out FitCount, Dx, out sz);
IntPtr cfont = SelectObject(hDC, oldfnt);
DeleteObject(cfont);
e.Graphics.ReleaseHdc();
for (int i = 0; i < Dx.Length; i++) {
textBox1.Text += string.Format("{0:d}\r\n", Dx[i]);
}
TextFormatFlags.Default | TextFormatFlags.NoPadding
を
TextFormatFlagsオプションに指定して画面を描画します。sz
変数のcyに設定されていますので、
描画位置のY座標にsz.cy
の値を加算します。 int idx = 0;
int startidx = 0;
int startpos = 0;
int posx = areaLeft;
int posy = areaTop;
while (idx < Dx.Length - 1) {
if (areaWidth < Dx[idx + 1] - startpos) {
string drawText = DocText.Substring(startidx, idx - startidx + 1);
TextRenderer.DrawText(e.Graphics, drawText, f, new Rectangle(posx,posy,areaWidth,sz.cy),
Color.Black, TextFormatFlags.Default | TextFormatFlags.NoPadding);
posy += sz.cy;
startidx = idx + 1;
startpos = Dx[idx];
}
idx++;
}
string lastdrawText = DocText.Substring(startidx);
TextRenderer.DrawText(e.Graphics, lastdrawText, f, new Rectangle(posx, posy, areaWidth, sz.cy),
Color.Black, TextFormatFlags.Default | TextFormatFlags.NoPadding);