开发者

DrawString property within a rectangle with multiple fonts c#

开发者 https://www.devze.com 2023-03-18 16:26 出处:网络
I\'m using C# WinForms and GDI+ to do something I hoped wouldn\'t be too much problem but... I\'m basically trying to draw a string within a rectangle that has 开发者_运维知识库highlighted sections w

I'm using C# WinForms and GDI+ to do something I hoped wouldn't be too much problem but...

I'm basically trying to draw a string within a rectangle that has 开发者_运维知识库highlighted sections within the string. This all works fine when printing on one line, but I have issues when trying to wrap the text onto the next line within the rectangle.

The algorithm used is as follows: -

Split strings into a collection of highlight and not highlight.

Do

  If Highlightedtext Then

    DrawString(HighLightedText);
    Move X position forward to next character space

  Else

    DrawString(NormalText);
    Move X position forward to next character space

  End If

Loop

I would put the code in, but it's messy and long (i'm maintaining it). It'll print out find if the text is one string of either highlighting or not, as it'll wrap it within the bounds of the rectangle without issue if it's too long. If it's multiple highlighting and the string is bigger than the rectangle, it'll write outside of it... this is because the "move X position forward..." just moves the rectangle on which is a problem!

I want to essentially move the point the text is printed within the original rectangle and print it on the next line if wrapping is required. Can anyone assist with this? It's a real pain!


I've managed to sort this by having to make my function do one character at a time.

To do this, I made a function to get an array (which is the length of the string itself) of boolean values which have set any highlighted characters to true.

private bool[] Get_CharacterArray(string text)
    {
        // Declare the length of the array, all set to false
        bool[] characters = new bool[text.Length];

        // Get the matching points
        List<Point> wordLocs = FindMatchingTerms(text);
        wordLocs.Sort(PointComparison);

        int position = 0;
        foreach (Point loc in wordLocs)
        {
            // We're only setting the array for matched points
            for (position = loc.X; position <= loc.Y; position++)
            {
                characters[position] = true;
            }
        }

        // Return the array
        return characters;
    }

(FindMatchingTerms() is a function that will look in the string and return the matches found into a collection).

I then loop this array to draw it out to screen but keeping track of my rectangle border width. When it reduces to the relevant size, I reset the position of drawing back to the start and then move the starting Y position down a bit.

private void RenderFormattedText(Graphics g, RectangleF bounds, string text, string matchText, Font font, Color colour, bool alignTextToTop)
            {
                const string spaceCharacter = " ";
                const string hyphenCharacter = "-";
                Font fr = null;
                Font fi = null;
                try
                {
                    // Get teh matching characters.
                    bool[] charactersMatched = Get_CharacterArray(text);

                    // Setup the fonts and bounds.
                    fr = new Font(font.FontFamily, font.Size, FontStyle.Regular);
                    fi = new Font(font.FontFamily, font.Size, FontStyle.Bold | FontStyle.Underline);
                    SizeF fontSize = g.MeasureString(text, fi, 0, StringFormat.GenericTypographic);
                    RectangleF area = bounds;

                    // Loop all the characters of the phrase
                    for (int pos = 0; pos < charactersMatched.Length; pos++)
                    {
                        // Draw the character in the appropriate style.
                        string output = text.Substring(pos, 1);
                        if (charactersMatched[pos])
                        {
                            area.X += DrawFormattedText(g, area, output, fi, colour);
                        }
                        else
                        {
                            area.X += DrawFormattedText(g, area, output, fr, colour);
                        }

                        // Are we towards the end of the line?
                        if (area.X > (bounds.X + bounds.Width - 1))
                        {
                            // are we in the middle of a word?
                            string preOutput = spaceCharacter;
                            string postOutput = spaceCharacter;

                            // Get at the previous character and after character
                            preOutput = text.Substring(pos - 1, 1);
                            if ((pos + 1) <= text.Length)
                            {
                                postOutput = text.Substring(pos + 1, 1);
                            }

                            // Are we in the middle of a word? if so, hyphen it!
                            if (!preOutput.Equals(spaceCharacter) && !postOutput.Equals(spaceCharacter))
                            {
                                if (charactersMatched[pos])
                                {
                                    area.X += DrawFormattedText(g, area, hyphenCharacter, fi, colour);
                                }
                                else
                                {
                                    area.X += DrawFormattedText(g, area, hyphenCharacter, fr, colour);
                                }
                            }
                        }

                        // Are we at the end of the line?
                        if (area.X > (bounds.X + bounds.Width))
                        {
                            area.X = bounds.X;
                            area.Y += fontSize.Height + 2;
                        }
                    }
                }
                finally
                {
                    fr.Dispose();
                    fi.Dispose();
                }
            }

Hopefully someone else will find this useful :) I've got some constants in there for spaceCharacter and hypenCharacter which should be self explanatory! There are custom functions to draw the string, but it should make sense nonetheless, hope it helps anyone else.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号