简体   繁体   English

Graphics.DrawString到多个矩形

[英]Graphics.DrawString to multiple rectangles

I am trying to write a function that needs to draw a string to an image. 我正在尝试编写一个需要在图像上绘制字符串的函数。 The image has anywhere from 1-5 textboxes, which each have ax,y, width, and height. 图像具有1-5个文本框,其中每个都有ax,y,宽度和高度。 These details are defined in an XML file which I am parsing, so I have access to these for each box. 这些详细信息在我正在解析的XML文件中定义,因此我可以访问每个框。

My question is whether or not I can use the graphics.DrawString (or a similar) method to do this easily. 我的问题是我是否可以使用graphics.DrawString(或类似的方法)轻松地做到这一点。 The sample function below will create a rectangle with specified x,y, width, height, and then draw a string within. 下面的示例函数将创建一个具有指定的x,y,宽度,高度的矩形,然后在其中绘制一个字符串。 If the string doesn't fit, it truncates. 如果字符串不合适,它将被截断。

    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);
    }

What I want instead of this, is rather than truncating, it will stop at the last fitting word, and go to the next rectangle(textbox). 我要代替它而不是被截断,它会停在最后一个合适的单词处,然后转到下一个矩形(文本框)。 This way I can use all the available textboxes. 这样,我可以使用所有可用的文本框。

Is there a method already made to do this? 已经有一种方法可以做到这一点吗? Otherwise I will need to implement my own drawString method. 否则,我将需要实现自己的drawString方法。

OK, what you would have to do is loop through each char in the string, and concatenate to a final string.. so basically foreach (char c in mystring)... then using measurestring, you check to see if the string is over the box length, if it is, start on the next rect... 好的,您要做的是循环遍历字符串中的每个字符,并连接到最终字符串..因此,基本上是foreach(mystring中的char c)...然后使用measurestring,检查字符串是否结束盒子的长度,如果是的话,从下一个矩形开始...

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

This solution uses the StringFormat 's settings to ensure that each call to DrawString only draws the words that fit. 此解决方案使用StringFormat的设置来确保对DrawString的每次调用仅绘制适合的单词。 Then, Graphics.MeasureCharacterRanges calculates the words that don't fit into the rectangle, and the remaining text overflows into the next layout rectangle. 然后, Graphics.MeasureCharacterRanges计算不适合该矩形的单词,其余文本溢出到下一个布局矩形中。

You might need to customize how the input string is split into words. 您可能需要自定义如何将输入字符串拆分为单词。 Right now I'm just splitting it apart at whitespace boundaries. 现在,我只是将其在空白边界处分开。

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 = "";
    }

This is what I have. 这就是我所拥有的。 It does what I described. 它做了我所描述的。 Thanks for the answers. 感谢您的回答。

    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();
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM