如何使用面板上的图形类绘制多色文本? [英] How can I draw multi-colored text using graphics class on panel?

查看:322
本文介绍了如何使用面板上的图形类绘制多色文本?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在面板上绘制以下文本:

I want to draw the following text on panel:

这是一种彩色的文本.

我发现了此文章关于绘制彩色文本.

I found this article about drawing multicolored text.

我用单词替换了字符,但不起作用.

I replaced characters with words but it doesn't work.

(我使用FillPath/DrawPath绘制文本)

(I use FillPath/DrawPath to draw text)

我的代码:

private void Form1_Paint(object sender, PaintEventArgs e)
    {
        const string txt = "C# Helper! Draw some text with each letter in a random color.";

        // Make the font.
        using (Font the_font = new Font("Times New Roman", 40,
            FontStyle.Bold | FontStyle.Italic))
        {
            // Make a StringFormat object to use for text layout.
            using (StringFormat string_format = new StringFormat())
            {
                // Center the text.
                string_format.Alignment = StringAlignment.Center;
                string_format.LineAlignment = StringAlignment.Center;
                string_format.FormatFlags = StringFormatFlags.NoClip;

                // Make CharacterRanges to indicate which
                // ranges we want to measure.

                MatchCollection mc = Regex.Matches(txt, @"[^\s]+");
                CharacterRange[] ranges = new CharacterRange[mc.Count];
                int g = 0;
                foreach (Match m in mc)
                {
                    ranges[g] = new CharacterRange(m.Index, m.Length);
                    g++;
                }
                string_format.SetMeasurableCharacterRanges(ranges);

                // Measure the text to see where each character range goes.
                Region[] regions =
                    e.Graphics.MeasureCharacterRanges(
                        txt, the_font, this.ClientRectangle,
                        string_format);

                // Draw the characters one at a time.
                for (int i = 0; i < ranges.Length; i++)
                {
                    // See where this character would be drawn.
                    RectangleF rectf = regions[i].GetBounds(e.Graphics);
                    Rectangle rect = new Rectangle(
                        (int)rectf.X, (int)rectf.Y,
                        (int)rectf.Width, (int)rectf.Height);

                    // Make a brush with a random color.
                    using (Brush the_brush = new SolidBrush(RandomColor()))
                    {
                        // Draw the character.
                        string txts = txt.Substring(ranges[i].First, ranges[i].Length);
                        e.Graphics.DrawString(txts,
                            the_font, the_brush, rectf, string_format);
                    }
                }
            }
        }
    }

出什么问题了?

推荐答案

(从某种意义上来说)这是经典之作.
MeasureCharacterRanges Graphics.DrawString执行的实际字符串绘制.

This is (in a way) a classic.
There is a discrepancy between the quite precise measure performed by MeasureCharacterRanges and the actual string drawing performed by Graphics.DrawString.

Region.GetBounds()返回的RectagleF会按原样考虑文本的大小.
另一方面,Graphics.DrawString在计算给定范围内的Text布局时执行某种网格拟合.

The RectagleF returned by Region.GetBounds() considers the measure of the Text as it is.
Graphics.DrawString, on the other hand, performs a sort of grid-fitting when calculating a Text disposition inside the given bounds.

我不会在这里解释它,这是一个很广泛的问题,但是我已经写了一些关于它的内容:

I won't explain it here, it's quite a broad matter, but I've written something about it already:
Drawing a Long String on to a Bitmap results in Drawing Issues.
If you're interested, you can find some details on the Graphics object behaviour in this context.

它的总和是,正确测量了文本,但是Graphics.DrawString执行的调整导致文本不完全适合所测量的范围:绘制的文本稍微溢出. br>

The sum of it is, the Text is measured correctly, but the adjustments that Graphics.DrawString performs, cause the Text to not fit completely in the measured bounds: the drawn Text slightly overflows.

您可以使用几个StringFormat标志来更正此问题:
添加

You could correct this problem using a couple of StringFormat flags:
Add [StringFormat].Trimming = StringTrimming.None

应用此设置后,您可以立即看到问题所在:最后一个字符(或几个字符)被包装到新行中,使图形混乱.

With this setting applied, you can immediately see what the problem is: the last char (or few chars) are wrapped to a new line, messing up the drawing.

要更正它,请添加

To correct it, add StringFormatFlags.NoWrap to StringFormatFlags.NoClip
This will, apparently, solve the problem. Apparently because now the whole string is drawn on a single line.

我建议您使用

I propose you another method, using TextRenderer.DrawText to render the strings.
Note that TextRenderer is actually the class used by the WinForms controls (well, not all of them) to render Text to the screen.

这是使用以下方法得出的结果:

This is the result using the method that follows:

示例代码,使用原始代码进行了一些修改:

Sample code, using your original code with some modifications:

private void panel1_Paint(object sender, PaintEventArgs e)
{
    Control control = sender as Control;
    const string txt = "C# Helper! Draw some text with each word in a random color.";

    TextFormatFlags flags = TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter |
                            TextFormatFlags.NoPadding | TextFormatFlags.NoClipping;

    using (StringFormat format = new StringFormat())
    {
        format.Alignment = StringAlignment.Center;
        format.LineAlignment = StringAlignment.Center;

        MatchCollection mc = Regex.Matches(txt, @"[^\s]+");
        CharacterRange[] ranges = mc.Cast<Match>().Select(m => new CharacterRange(m.Index, m.Length)).ToArray();
        format.SetMeasurableCharacterRanges(ranges);

        using (Font font = new Font("Times New Roman", 40, FontStyle.Regular, GraphicsUnit.Point))
        {
            Region[] regions = e.Graphics.MeasureCharacterRanges(txt, font, control.ClientRectangle, format);

            for (int i = 0; i < ranges.Length; i++)
            {
                Rectangle WordBounds = Rectangle.Round(regions[i].GetBounds(e.Graphics));
                string word = txt.Substring(ranges[i].First, ranges[i].Length);

                TextRenderer.DrawText(e.Graphics, word, font, WordBounds, RandomColor(), flags);
            }
        }
    }
}


private Random rand = new Random();
private Color[] colors =
{
    Color.Red,
    Color.Green,
    Color.Blue,
    Color.Lime,
    Color.Orange,
    Color.Fuchsia,
};

private Color RandomColor()
{
    return colors[rand.Next(0, colors.Length)];
}

这篇关于如何使用面板上的图形类绘制多色文本?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆