绘制多个没有重叠文本的字符串

时间:2018-07-14 19:13:37

标签: c# .net winforms system.drawing

我想在C#中的矩形上打印多个不同的字符串。

我的问题是,当我打印字符串时,它们总是重叠的。
我不能打印整个字符串,因为每一行都有另一种字体。

RectangleF[] rectangles = { 
    new RectangleF(650.8188976377953F, 57.48031496062993F, 275.59055118110234F, 334.6456692913386F) 
};

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

e.Graphics.DrawRectangles(blackPen, rectangles);
e.Graphics.DrawString("test1", headLine, black,rectangles[0],stringFormat);
e.Graphics.DrawString("test2", subLines, black, rectangles[0], stringFormat);

如何绘制它们,以使它们不重叠并将其放置在我想要的任何位置而无需使用坐标?

2 个答案:

答案 0 :(得分:3)

您的字符串重叠是因为您有一个绘制区域(rectangles[0]),所有字符串都绘制在该区域中,而没有关于它们位置的任何进一步说明。
由于StringFormat.LineAlignment设置为StringAlignment.Center,因此所有文本都绘制在rectangles[0]定义的区域的中心。

要在绘画区域内居中放置一系列字符串,您可以想象一下您的字符串序列,加上将它们分开的空间,以矩形显示。
要将这个Rectangle(绘图区域)居中放置在Container对象中,可以将这些零件之间的关系定义为:

Drawing Area Height = (Text Height * Number of Strings) + (Interline * (Number of Strings - 1))

Blank Area Height = (Container Height - Drawing Area Height)

然后,虚拟绘图区域在其容器内的居中位置为:

Container Top + (Blank Area Height / 2)

现在,我们知道从哪里开始绘制文本行了。所有其他字符串位置都相对于已经计算的“绘图区域”(因为它们都是该度量的一部分)。
这样,您无需手动将字符串放置在Container中。


要定义不同的字符串及其相对属性(文本,字体,字体类型,文本高度,文本颜色),我使用了List<Tuple>

List<Tuple<string, string, FontStyle, float, Brush>> DrawingStrings = new List<Tuple<string, string, FontStyle, float, Brush>>()
{
    new Tuple<string, string, FontStyle, float, Brush>("Text", "Font", FontStyle, Height, Brush),
    //(...)
}

但是您也可以使用List<[Class]>或您认为合适的其他任何适当的对象。

文本行由中间行分隔。
您可以修改此值并指定其他行距:

float Interline = 12.0F;

“容器”矩形(rectangles[0])内的“文本”位置是自动计算的。
因此,您可以在列表中添加更多字符串,并相应地定位它们。

e.Graphics.TextRenderingHint = TextRenderingHint.AntiAlias;

List<RectangleF> rectangles = new List<RectangleF>() {
    new RectangleF(5.8188976377953F, 5.48031496062993F, 170.59055118110234F, 170.6456692913386F)
};

List<Tuple<string, string, FontStyle, float, Brush>> DrawingStrings = new List<Tuple<string, string, FontStyle, float, Brush>>()
{
    new Tuple<string, string, FontStyle, float, Brush>("A Graphics", "Arial", FontStyle.Regular, 20F, Brushes.LightGreen),
    new Tuple<string, string, FontStyle, float, Brush>("String Drawing", "Segoe UI", FontStyle.Regular, 17F, Brushes.Orange),
    new Tuple<string, string, FontStyle, float, Brush>("Example", "Calibri", FontStyle.Regular, 22F, Brushes.SteelBlue)
};

float Interline = 12.0F;
float TextHeigh = - Interline + (DrawingStrings.Select(tp => tp.Item4 + Interline).Sum());
float TextPosition = ((rectangles[0].Height - TextHeigh + Interline) / 2);

StringFormat TextFormat = new StringFormat() {
    Alignment = StringAlignment.Center,
    LineAlignment = StringAlignment.Center,
    FormatFlags = StringFormatFlags.NoClip,
    Trimming = StringTrimming.EllipsisWord
};

foreach (Tuple<string, string, FontStyle, float, Brush> item in DrawingStrings)
{
    rectangles.Add(new RectangleF()
    {
        Width = rectangles[0].Width,
        Location = new PointF(rectangles[0].X, TextPosition),
        Height = item.Item4
    });
    TextPosition += item.Item4 + Interline;
};
//e.Graphics.DrawRectangles(Pens.White, rectangles.ToArray());

int RectArea = 0;
foreach (Tuple<string, string, FontStyle, float, Brush> item in DrawingStrings)
{
    RectArea += 1;
    using (Font font = new Font(item.Item2, item.Item4, item.Item3, GraphicsUnit.Pixel))
        e.Graphics.DrawString(item.Item1, font, item.Item5, rectangles[RectArea], TextFormat);
};

这是您在代码中看到的List<Tuple>的结果,以及如果添加另一行Text会发生的情况:

enter image description here enter image description here

如果取消注释此行:e.Graphics.DrawRectangles(Pens.White, rectangles.ToArray());,则可以看到如何使用不同的行间值来调整矩形的大小:

enter image description here enter image description here

     Interline 12.0F          Interline 16.0F

答案 1 :(得分:0)

您可以通过以下方式获取绘制的字符串大小:

Graphics.MeasureString("test1", StringFont)

然后,您可以从返回的大小点扩展矩形目标。