计算.NET DrawingContext DrawText方法中的文本环绕

时间:2011-01-19 23:57:59

标签: c# text system.drawing

我正在开展一个项目,让我近似文本呈现为图像和文本的DHTML编辑器。使用.NET 4 DrawingContext对象的DrawText方法呈现图像。

DrawText方法将文本与字体信息以及尺寸一起使用,并计算使文本尽可能合适所需的包装,如果文本太长则在末尾放置省略号。所以,如果我有以下代码在Rectangle中绘制文本,它将缩写它:

string longText = @"A choice of five engines, although the 2-liter turbo diesel, supposedly good for 48 m.p.g. highway, is not coming to America, at least for now. A 300-horsepower supercharged gasoline engine will likely be the first offered in the United States. All models will use start-stop technology, and fuel consumption will decrease by an average of 19 percent across the A6 lineup. A 245-horsepower A6 hybrid was also unveiled, but no decision has yet been made as to its North America sales prospects. Figure later in 2012, if sufficient demand is detected.";

var drawing = new DrawingGroup();
using (var context = drawing.Open())
{
    var text = new FormattedText(longText,
        CultureInfo.CurrentCulture,
        FlowDirection.LeftToRight,
        new Typeface("Calibri"),
        30,
        Brushes.Green);
    text.MaxTextHeight = myRect.Height;
    text.MaxTextWidth = myRect.Width;

    context.DrawText(text, new Point(0, 0));
}

var db = new DrawingBrush(drawing);
db.Stretch = Stretch.None;
myRect.Fill = db;

有没有办法计算文本的包装方式?在这个例子中,输出的文本包裹在“2升”和“48 m.p.g”等,如下图所示: alt text

2 个答案:

答案 0 :(得分:3)

您可以使用Graphics.MeasureString(String,Font,Int32)函数。您传递字符串,字体和最大宽度。它返回一个SizeF,它将形成矩形。您可以使用它来获得总高度,从而获得行数:

Graphics g = ...;
Font f = new Font("Calibri", 30.0);
SizeF sz = g.MeasureString(longText, f, myRect.Width);
float height = sz.Height;
int lines = (int)Math.round(height / f.Height); // overall height divided by the line height = number of lines

获取Graphics对象有很多种方法,任何方法都可以,因为你只是用它来测量而不是绘制(你可能需要更正它的DpiX,DpiY和PageUnit字段,因为这些效果测量。

获取Graphics对象的方法:

Graphics g = e.Graphics; // in OnPaint, with PaintEventArgs e
Graphics g = x.CreateGrahics(); // where x is any Form or Control
Graphics g = Graphics.CreateFrom(img); // where img is an Image.

答案 1 :(得分:2)

不确定您是否仍需要解决方案或此特定解决方案是否适合您的应用,但如果您在using块之后插入以下代码段,则会在每行显示文字(因此文本被打破以进行包装)。

我使用非常犹太人/游击队的方法来解决这个问题,只是在调试时浏览属性,寻找包装的文本片段 - 我发现它们并且它们处于可访问的属性中......所以你去了。很可能是一种更恰当/直接的方式。

// Object heirarchy:
// DrawingGroup (whole thing)
//  - DrawingGroup (lines)
//     - GlyphRunDrawing.GlyphRun.Characters (parts of lines)

// Note, if text is clipped, the ellipsis will be placed in its own 
// separate "line" below.  Give it a try and you'll see what I mean.

List<DrawingGroup> lines = drawing.Children.OfType<DrawingGroup>().ToList();

foreach (DrawingGroup line in lines)
{
    List<char> lineparts = line.Children
        .OfType<GlyphRunDrawing>()
        .SelectMany(grd => grd.GlyphRun.Characters)
        .ToList();

    string lineText = new string(lineparts.ToArray());

    Debug.WriteLine(lineText);
}
是的,嗨大卫。 : - )