6

私の問題:

私は現在、テキストの一部 (それぞれが異なるフォントを持つ可能性があります) を 1 行に表示するカスタム ユーザー コントロールに取り組んでいます。これらすべてのテキストを共通のベースラインに正確に揃えたいと思います。例えば:

  Hello,    I am    George.  
------------------------------   <- all text aligns to a common baseline
    ^         ^        ^
    |         |        |
 Courier    Arial    Times       <- font used for a particular bit of text
  20pt      40pt     30pt

これを直接行うための GDI+ 機能が見つからないため、独自の方法を考え出しました (以下に概要を示します)。でも:

これを実現する簡単な方法は本当にないのだろうか?

私の現在のアプローチ:

1)System.Drawing.Fontテキストの描画に使用されるすべての のリストを収集します。

2)各 についてFont、次のコードを使用して、ベースラインの垂直位置をピクセル単位で見つけます。

// variables used in code sample (already set)
Graphics G;
Font font;
...

// compute ratio in order to convert from font design units to pixels:
var designUnitsPerPixel = font.GetHeight(G) / 
                          font.FontFamily.GetLineSpacing(font.Style);

// get the cell ascent (baseline) position in design units:
var cellAscentInDesignUnits = font.FontFamily.GetCellAscent(font.Style);

// finally, convert the baseline position to pixels:
var baseLineInPixels = cellAscentInDesignUnits * designUnitsPerPixel;

3)使用されるすべてFontの について、上記で計算された最大baseLineInPixels値を決定し、この値を に保存しますmaxBaseLineInPixels

4)次の方法でテキストの各ビットを描画します。

// variables used in code sample (already set):
Graphics G;
Font font;
string text;
...

// find out how much space is needed for drawing the text
var measureF = G.MeasureString(text, font);

// determine location where text will be drawn:
var layoutRectF = new RectangleF(new PointF(0f, 0f), measureF);
layoutRectF.Y += maxBaseLineInPixels - baseLineInPixels;
// ^ the latter value 'baseLineInPixels' is specific to the font used

// draw text at specified location
G.DrawString(text, font, Brushed.Black, layoutRectF);

私は何かを見逃していますか、それとも本当に簡単な方法はありませんか?

4

2 に答える 2

0

この方法は仕事だと思いますので、ぜひお試しください。

List<RectangleF> rects = new List<RectangleF>();

private void Form1_Paint(object sender, PaintEventArgs e)
{
    ////////////////////Not Set baseLine
    //baseline
    e.Graphics.DrawLine(Pens.Red , new Point(100,200),new Point(800,200));

    //words
    Point point = new Point(100,100);
    e.Graphics.DrawString("hello world", new Font("Times", 30), Brushes.Black, point);
    RectangleF rectangleF = new RectangleF(point, e.Graphics.MeasureString("hello world", new Font("Times", 30)));
    e.Graphics.DrawRectangle(Pens.Green,rectangleF.X ,rectangleF.Y , rectangleF.Width , rectangleF.Height);
    rects.Add(rectangleF);

    point = new Point(400, 100);
    e.Graphics.DrawString("hello world", new Font("Arial", 40), Brushes.Black, point);
    rectangleF = new RectangleF(point, e.Graphics.MeasureString("hello world", new Font("Arial", 40)));
    e.Graphics.DrawRectangle(Pens.Green, rectangleF.X, rectangleF.Y, rectangleF.Width, rectangleF.Height);
    rects.Add(rectangleF);

    point = new Point(800, 100);
    e.Graphics.DrawString("hello world", new Font("Courier", 20), Brushes.Black, point);
    rectangleF = new RectangleF(point, e.Graphics.MeasureString("hello world", new Font("Courier", 20)));
    e.Graphics.DrawRectangle(Pens.Green, rectangleF.X, rectangleF.Y, rectangleF.Width, rectangleF.Height);
    rects.Add(rectangleF);

    ///////////////////SetBaseLine/////////////////////////////
    var maxHeight = GetMaxHeight();
    ///////////////////

    //baseLine
    e.Graphics.DrawLine(Pens.Pink, new Point(100, (int) (400 + maxHeight / 2)), new Point(800, (int) (400 + maxHeight / 2)));

    StringFormat stringFormat = new StringFormat();
    stringFormat.LineAlignment = StringAlignment.Center;

    //words
    point = new Point(100, 400);
    rectangleF = new RectangleF(point, e.Graphics.MeasureString("hello world", new Font("Times", 30)));
    e.Graphics.DrawString("hello world", new Font("Times", 30), Brushes.Black, new RectangleF(rectangleF.X ,rectangleF.Y , rectangleF.Width , maxHeight) , stringFormat);
    e.Graphics.DrawRectangle(Pens.Green, rectangleF.X, rectangleF.Y, rectangleF.Width, rectangleF.Height);
    rects.Add(rectangleF);

    point = new Point(400, 400);
    rectangleF = new RectangleF(point, e.Graphics.MeasureString("hello world", new Font("Arial", 40)));
    e.Graphics.DrawString("hello world", new Font("Arial", 40), Brushes.Black, new RectangleF(rectangleF.X, rectangleF.Y, rectangleF.Width, maxHeight), stringFormat);
    e.Graphics.DrawRectangle(Pens.Green, rectangleF.X, rectangleF.Y, rectangleF.Width, rectangleF.Height);
    rects.Add(rectangleF);

    point = new Point(800, 400);
    rectangleF = new RectangleF(point, e.Graphics.MeasureString("hello world", new Font("Courier", 20)));
    e.Graphics.DrawString("hello world", new Font("Courier", 20), Brushes.Black, new RectangleF(rectangleF.X, rectangleF.Y, rectangleF.Width, maxHeight), stringFormat);
    e.Graphics.DrawRectangle(Pens.Green, rectangleF.X, rectangleF.Y, rectangleF.Width, rectangleF.Height);
    rects.Add(rectangleF);

}

private float GetMaxHeight()
{
    float temp = 0;
    foreach (RectangleF rectangleF in rects)
        if (rectangleF.Height > temp)
            temp = rectangleF.Height;

    return temp;
}
于 2011-06-12T15:04:17.050 に答える
0

私はここ数日同じことを研究してきましたが、最終的にこのブログページで答えを見つけました。このコード (記事の一番下) は私にとって非常にうまく機能し、この問題に苦しんでいる他の人に役立つことを願っています:

private void DrawOnBaseline(string s, Graphics g, Font f, Brush b, Point pos)
    {
      float baselineOffset=f.SizeInPoints/f.FontFamily.GetEmHeight(f.Style)*f.FontFamily.GetCellAscent(f.Style);
      float baselineOffsetPixels = g.DpiY/72f*baselineOffset;

      g.DrawString(s,f,b,new Point(pos.X,pos.Y-(int)(baselineOffsetPixels+0.5f)),StringFormat.GenericTypographic);
    }
于 2014-06-23T22:04:01.637 に答える