Graphics.DrawString 到多个矩形

Graphics.DrawString to multiple rectangles

我正在尝试编写一个需要将字符串绘制到图像的函数。该图像有 1-5 个文本框,每个文本框都有 x、y、宽度和高度。这些详细信息在我正在解析的 XML 文件中定义,因此我可以访问每个框的这些信息。

我的问题是我是否可以使用 graphics.DrawString(或类似的)方法轻松地做到这一点。下面的示例函数将创建一个具有指定 x、y、宽度、高度的矩形,然后在其中绘制一个字符串。如果字符串不适合,它会被截断。

    public void DrawStringRectangleFormat(Graphics g)
    {
        // Create string to draw.
        String drawString = "Sample Text is too long to fit into this tiny lil rectangle area right here";

        // Create font and brush.
        Font drawFont = new Font("Arial", 16);
        SolidBrush drawBrush = new SolidBrush(Color.Black);

        // Create rectangle for drawing.
        float x = 150.0F;
        float y = 150.0F;
        float width = 200.0F;
        float height = 50.0F;
        RectangleF drawRect = new RectangleF(x, y, width, height);

        // Set format of string.
        StringFormat drawFormat = new StringFormat();
        drawFormat.Alignment = StringAlignment.Center;

        // Draw string to screen.
        g.DrawString(drawString, drawFont, drawBrush, drawRect, drawFormat);
    }

我想要的不是截断,而是在最后一个合适的单词处停止,然后转到下一个矩形(文本框)。这样我就可以使用所有可用的文本框。

是否已经有方法可以做到这一点?否则我将需要实现我自己的 drawString 方法。

好的,您需要做的是遍历字符串中的每个字符,并连接成最终的字符串.. 所以基本上是foreach(mystring中的char c)...... 然后使用 measurestring,检查字符串是否超过框长度,如果是,从下一个矩形开始...

https://msdn.microsoft.com/en-us/library/6xe5hazb(v=vs.110).aspx

这就是我的。它做了我描述的。感谢您的回答。

    public void DrawStringInTextboxes(string text, Graphics g)
    {

        String drawString = text;

        PrivateFontCollection fontCollection = new PrivateFontCollection();
        fontCollection.AddFontFile(System.Web.Hosting.HostingEnvironment.MapPath("~/Content/Fonts/Squidgingtons.ttf"));
        var squidingtonsFontFamily = fontCollection.Families[0];
        Font squidingtons = new Font(squidingtonsFontFamily, textParameters[0].MaxFontSize);
        Font drawFont = new Font("Arial", 60);
        SolidBrush drawBrush = new SolidBrush(Color.Black);

        StringFormat drawFormat = new StringFormat();
        drawFormat.Alignment = StringAlignment.Center;

        char[] delimiterChars = { ' ' };
        string[] words = drawString.Split(delimiterChars);
        string finalString = "";
        int textBoxIndex = 0;

        foreach (string word in words)
        {
            //set the dimensions for the first textbox and create a rectangle with those specifications.
            float x = textParameters[textBoxIndex].Left;
            float y = textParameters[textBoxIndex].Top;
            float width = textParameters[textBoxIndex].Width;
            float height = textParameters[textBoxIndex].Height;
            RectangleF Rect = new RectangleF(x, y, width, height);
            //if the current finalString + the next word fits in the current box, add the word to finalString.
            if (g.MeasureString(finalString + word + " ", squidingtons).Width < textParameters[textBoxIndex].Width) 
            {     
                finalString = finalString + " " + word;
                //if this is the last word, print the finalString and we are done.
                if (word == words[words.Length - 1])
                {
                    g.DrawString(finalString, squidingtons, drawBrush, Rect, drawFormat);
                    break;
                }

            }
            //the current finalString + next word did not fit in the box. Draw what we have to the first box.
            else {
                g.DrawString(finalString, squidingtons, drawBrush, Rect, drawFormat);
                //Hold onto the word that didnt fit. It will be the first word of the next box.
                finalString = word;
                if (textBoxIndex +1 >= textParameters.Length)
                {
                    //if we are out of textboxes, we are done.
                    break;
                }
                else
                {
                    //move on to the next textbox. The loop begins again with new specifications set for the textbox.
                    textBoxIndex++;
                }
            }

        }
        squidingtons.Dispose();
        drawBrush.Dispose();
        drawFont.Dispose();
    }

此解决方案使用 StringFormat 的设置来确保每次调用 DrawString 仅绘制适合的单词。然后,Graphics.MeasureCharacterRanges计算不适合矩形的单词,剩余的文本溢出到下一个布局矩形。

您可能需要自定义将输入字符串拆分为单词的方式。现在我只是在空白边界将它分开。

using System.Text.RegularExpressions;
using System.Drawing;

/// <summary>
/// Draw a string using one or more layout rectangles.  Words which don't fit will overflow into the next layout rectangle.
/// </summary>
private static void DrawOverflowString(Graphics graphics, string drawString, RectangleF[] layoutRectangles, StringAlignment alignment)
{
    var drawFont = new Font("Arial", 16.0f);
    var black = new SolidBrush(Color.Black);
    var format = new StringFormat()
    {
        Alignment = alignment,
        Trimming = StringTrimming.Word,
        FormatFlags = StringFormatFlags.LineLimit
    };
    var wordRegex = new Regex("[^\s]+");
    string remainingText = drawString;
    foreach (var layoutRect in layoutRectangles)
    {
        // Draw everything that will fit into this text box
        graphics.DrawString(remainingText, drawFont, black, layoutRect, format);

        // calculate which words did not fit
        var wordMatches = wordRegex.Matches(remainingText);
        var ranges = wordMatches.OfType<Match>().Select(x => new CharacterRange(x.Index, x.Length)).ToArray();
        format.SetMeasurableCharacterRanges(ranges);
        var wordRegions = graphics.MeasureCharacterRanges(remainingText, drawFont, layoutRect, format);

        var allfit = true;
        for (int i = 0; i < wordRegions.Length; i++)
        {
            if (wordRegions[i].GetBounds(graphics).Width == 0.0f)
            {
                allfit = false;
                remainingText = remainingText.Substring(wordMatches[i].Index);
                break;
            }
        }

        if (allfit)
            break;
    }

    drawFont.Dispose();
    black.Dispose();
}
        protected override void OnPaint(PaintEventArgs e)
    {
        // Call the OnPaint method of the base class.
        base.OnPaint(e);
        List<Rectanglestring> testrecs = new List<Rectanglestring>();
        testrecs.Add(new Rectanglestring { targetrect = new Rectangle(0, 12, 40, 12), whattodraw = "" });
        testrecs.Add(new Rectanglestring {targetrect= new Rectangle(0, 25, 35, 12),whattodraw="" });
        testrecs.Add(new Rectanglestring { targetrect = new Rectangle(0, 35, 35, 12), whattodraw = "" });
        testrecs.Add(new Rectanglestring { targetrect = new Rectangle(0, 45, 35, 12), whattodraw = "" });
        testrecs.Add(new Rectanglestring { targetrect = new Rectangle(0, 65, 35, 12), whattodraw = "" });
        testrecs.Add(new Rectanglestring { targetrect = new Rectangle(0, 85, 35, 12), whattodraw = "" });
        testrecs.Add(new Rectanglestring { targetrect = new Rectangle(0, 95, 55, 12), whattodraw = "" });
        string mystringtofit = "This is just an example";

        foreach (Rectanglestring rect in testrecs)
        {
            for (int i = 0; i < mystringtofit.Length; i++)
            {
                if (mystringtofit[i] == ' ' && rect.whattodraw.Length > 0) break;
                if (mystringtofit[i] == ' ') continue;
                string teststring = rect.whattodraw + mystringtofit[i];
                SizeF stringSize = stringSize = e.Graphics.MeasureString(teststring, new Font("Ariel", 12));
                if (stringSize.Width >= rect.targetrect.Width) break;
                rect.whattodraw += mystringtofit[i];


            }

            mystringtofit = mystringtofit.Substring(rect.whattodraw.Length);
            if (mystringtofit.StartsWith(" "))
            {
                mystringtofit = mystringtofit.Substring(1);
            }
            e.Graphics.DrawString(rect.whattodraw, Font, new SolidBrush(ForeColor), rect.targetrect);
        }
        // Call methods of the System.Drawing.Graphics object.

    }
    public class Rectanglestring
    {
       public Rectangle targetrect = new Rectangle();
       public string whattodraw = "";
    }