トップ回答者
LOGFONT構造体の横幅を取得する方法

質問
-
いつも大変お世話になっています。
開発環境:Win7 x86 Visual Studio 2013
文字列をFormに描画する際、文字の横幅を通常のx%に変更したいと考えています。
条件として、C++でTextOut()を使った描画と結果を同じにしたいのですが、
下記①のように、いったん通常サイズで描画した後、そのイメージをストレッチする方法では、
若干違い生じますし、斜体では、最初のMeasureTextで、文字列幅が必要な長さより短くなり、
後ろが切れてしまいます。
①ストレッチ
// 対象文字サイズ取得 nopadSize = TextRenderer.MeasureText(g, charEnum.Current.ToString(), font , new Size(GXSIZE, GXSIZE), TextFormatFlags.NoPadding | TextFormatFlags.NoPrefix); // 対象文字を描画 Bitmap imgChar = new Bitmap(nopadSize.Width, nopadSize.Height); Graphics cg = Graphics.FromImage(imgChar); TextRenderer.DrawText(cg, charEnum.Current.ToString(), font, new Point(0, 0), color , TextFormatFlags.NoPadding | TextFormatFlags.NoPrefix); // 文字列描画領域に横倍分ストレッチして描画 int stretchWidth = nopadSize.Width * wbai / 100; sg.DrawImage(imgChar, new Rectangle(posX, 0, stretchWidth, nopadSize.Height) , new Rectangle(0, 0, nopadSize.Width, nopadSize.Height) , GraphicsUnit.Pixel);
そこで、C++(下記②//*****部分)と同じ方法でフォントを作成しようと考えたのですが(下記③)、
VisualStyleRenderer.GetTextMetrics()の使い方がわかりません。ご指導、どうぞよろしくお願いいたします。
②c++ //*****部分
void LogFontSet(HDC hdc,PLOGFONT plf, PTCHAR facename, WORD style, WORD fsize, WORD wbai, char hou) { long l; int Height,Width; _tcscpy_s(plf->lfFaceName,facename); SetMapMode(hdc,MM_TEXT); FONTENUMPROC FontEnumProc=(FONTENUMPROC)EnumFontFamProc; EnumFontFamilies(hdc,plf->lfFaceName,FontEnumProc,(LPARAM)plf); Height=MulDiv(fsize,96,72); plf->lfHeight=-Height; if (style>=2) plf->lfWeight=FW_BOLD; else plf->lfWeight=FW_NORMAL; if (style&1) plf->lfItalic=1; if (hou>=0) { plf->lfEscapement=plf->lfOrientation=(int)hou*900; } plf->lfQuality=NONANTIALIASED_QUALITY; HFONT hFont; TEXTMETRIC tm; //********** GetTextMetricsで文字幅を取得し、x%倍(wbai)して、LOGFONT構造体に戻す hFont=(HFONT)SelectObject(hdc,CreateFontIndirect(plf)); GetTextMetrics(hdc,&tm); DeleteObject(SelectObject(hdc,hFont)); l=(long)tm.tmAveCharWidth*(long)wbai/100L; Width=(int)l; plf->lfWidth=-Width; }
③C# //********部分にどうコーディングすればよいか?
Font CreateFont(string fontname, int angleInDegrees) { // LogFont logf = new Microsoft.WindowsCE.Forms.LogFont(); LOGFONT logf = new LOGFONT(); // Create graphics object for the form, and obtain // the current DPI value at design time. In this case, // only the vertical resolution is petinent, so the DpiY // property is used. Graphics g = this.CreateGraphics(); // Scale an 18-point font for current screen vertical DPI. logf.lfHeight = (int)(-50f * g.DpiY / curDPI); // Convert specified rotation angle to tenths of degrees. logf.lfEscapement = angleInDegrees * 10; // Orientation is the same as Escapement in mobile platforms. logf.lfOrientation = logf.lfEscapement; logf.lfFaceName = fontname; // Set LogFont enumerations. logf.lfCharSet = define.DEFAULT_CHARSET; logf.lfOutPrecision = define.OUT_DEFAULT_PRECIS; logf.lfClipPrecision = define.CLIP_DEFAULT_PRECIS; logf.lfQuality = define.CLEARTYPE_QUALITY; logf.lfPitchAndFamily = define.DEFAULT_PITCH; //***************** ここで"lfWidth"を変更したい // Explicitly dispose any drawing objects created. g.Dispose(); return Font.FromLogFont(logf); }
kizakura_ui
回答
-
コンパイルを通るだけは書きましたが動作は保証しなかったので。
GDI+におけるFontオブジェクトは、LOGFONT::lfWidthは無視されるみたいですね。
Fontオブジェクトを使うのは諦めて、(Ext)TextOutで出力してください。
- 回答としてマーク kizakura_ui 2015年11月13日 11:35
すべての返信
-
VisualStyleRenderer自体は、VisualStyleElementクラス以下にツリー状に山ほど定義されている適切なVisualStyleElementを与えればnewできます。
// この辺の仕組みは詳しくないので、どのVisualStyleElementを与えるのが妥当かは知りません。
VisualStyleRenderer::GetTextMetricsは引数にIDeviceContextを要求し、Graphics型はこのインターフェイスを実装しているため直接渡すことが可能です。
しかし、Windows APIのHDCとは異なり、Graphics自体はフォント情報を持たず、描画の度にFontオブジェクトを受け取って処理するために、そのままではGetTextMetricsにこちら側が意図するフォント情報を与えることができません。
そうするには、Graphics::GetHdc()でHDCを取ってきて、SelectObject関数でフォントを選択する必要があります。選択後はGraphics::ReleaseHdc()で一旦解放してからGetTextMetricsにGraphicsを与えればいいです。
-
ご指導、ありがとうございます。
ご指摘いただいたことがよく理解できなかったのですが、
とりあえず、下記の”//******************** 追加部分”を追加したところ、
textMetric.tmAveCharWidthを取得することができました。
ただ、logf.lfWidthに取得値の3倍の値をセットしても、横長な文字列にはなりませんでした。
また、追加部分の処理をコメントにして、
logf.lfWidth = logf.lfHeight;
もやってみましたが、反映されませんでした。
お忙しいところ、大変申し訳ありませんが、具体的なコーディング方法をお教えいただけないでしょうか?
よろしくお願いいたします。
[DllImport("Gdi32.dll", EntryPoint = "CreateFontIndirect")] static extern IntPtr CreateFontIndirect(LOGFONT logf); [DllImport("Gdi32.dll", CharSet = CharSet.Auto)] static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj); [DllImport("Gdi32.dll", CharSet = CharSet.Auto)] static extern bool GetTextMetrics(IntPtr hdc, out TEXTMETRIC lptm); [DllImport("Gdi32.dll", CharSet = CharSet.Auto)] static extern bool DeleteObject(IntPtr hgdiobj); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] internal struct TEXTMETRIC { public int tmHeight; public int tmAscent; public int tmDescent; public int tmInternalLeading; public int tmExternalLeading; public int tmAveCharWidth; public int tmMaxCharWidth; public int tmWeight; public int tmOverhang; public int tmDigitizedAspectX; public int tmDigitizedAspectY; public char tmFirstChar; public char tmLastChar; public char tmDefaultChar; public char tmBreakChar; public byte tmItalic; public byte tmUnderlined; public byte tmStruckOut; public byte tmPitchAndFamily; public byte tmCharSet; } // Method to create a rotated font using a LOGFONT structure. Font CreateRotatedFont(string fontname, int angleInDegrees) { // LogFont logf = new Microsoft.WindowsCE.Forms.LogFont(); LOGFONT logf = new LOGFONT(); // Create graphics object for the form, and obtain // the current DPI value at design time. In this case, // only the vertical resolution is petinent, so the DpiY // property is used. Graphics g = this.CreateGraphics(); // Scale an 18-point font for current screen vertical DPI. logf.lfHeight = (int)(-50f * g.DpiY / curDPI); // Convert specified rotation angle to tenths of degrees. logf.lfEscapement = angleInDegrees * 10; // Orientation is the same as Escapement in mobile platforms. logf.lfOrientation = logf.lfEscapement; logf.lfFaceName = fontname; // Set LogFont enumerations. logf.lfCharSet = define.DEFAULT_CHARSET; logf.lfOutPrecision = define.OUT_DEFAULT_PRECIS; logf.lfClipPrecision = define.CLIP_DEFAULT_PRECIS; logf.lfQuality = define.CLEARTYPE_QUALITY; logf.lfPitchAndFamily = define.DEFAULT_PITCH; logf.lfItalic = 1; //******************** 追加部分 TEXTMETRIC textMetric; IntPtr hFont = CreateFontIndirect(logf); try { IntPtr hDC = g.GetHdc(); SelectObject(hDC, hFont); bool result = GetTextMetrics(hDC, out textMetric); } finally { DeleteObject(hFont); g.ReleaseHdc(); } int Width = textMetric.tmAveCharWidth * 300 / 100; logf.lfWidth = -Width; //******************** 追加部分 // Explicitly dispose any drawing objects created. g.Dispose(); return Font.FromLogFont(logf); }
kizakura_ui
-
コンパイルを通るだけは書きましたが動作は保証しなかったので。
GDI+におけるFontオブジェクトは、LOGFONT::lfWidthは無視されるみたいですね。
Fontオブジェクトを使うのは諦めて、(Ext)TextOutで出力してください。
- 回答としてマーク kizakura_ui 2015年11月13日 11:35