Make drawstring partially bold

2019-07-04 02:11发布

问题:

Good morning.

I have created a custom treeview control that paints a normal treeview onto the screen, plus various other things. During the paint event I draw the node.text string to the treeview control using the following method.

node.text = "ABCDEFG"
g.DrawString(node.Text, tvFont, Brushes.Black, strPosX + 10, bothPosY)

Basically what I am trying to do is make part of the node.text italic, so that it renders on screen like so...

AB*CDE*FG

Personally I would approach this in such a way that it effectively draws three different strings... two non-italic and one italic, however this would require additional positioning.

I am hoping that it is possible to effectively concatinate font formated strings then place that as the first parameter in drawstring, is this actually possible? If so how would I go about doing it and/or are there any resources that would help me.

I am using winforms, and visualbasic .net framework 3.5 (unfortuantly non of the aforementioned can be changed as it is a work project and this is the environment the software is designed for)

回答1:

I am hoping that it is possible to effectively concatinate font formated strings then place that as the first parameter in drawstring, is this actually possible?

No, this is not possible. The DrawString function is going to draw all of the text you specify using the formatting flags that you specify. It's an all-or-nothing affair.

If you want to make some portions bold and other portions not, then you will need to make multiple calls to the DrawString function. There is some additional positioning involved to accomplish that, but it shouldn't be too difficult. Only the x-coordinate is changing; the y-coordinate should stay the same. Unless you do something fancy like change font faces, then your baselines will get messed up and you will have to compensate for that to prevent the result from looking like an ugly mismatch.


Aside from that, allow me to recommend that you use the TextRenderer.DrawText function instead of the Graphics.DrawString function. The advantage of the former is that it draws text using GDI, which is the same way that the built-in native controls draw their text. There are a number of advantages to this consistency, not the least of which is a pleasing and harmonious visual appearance.

And if you're using TextRenderer.DrawText, you'll also want to make sure that you combine it with TextRenderer.MeasureText, because the measurements will be different from those returned by Graphics.MeasureString, which draws using GDI+.

More information on the difference between TextRenderer.DrawText and Graphics.DrawString is available in the answers to this question. Graphics.DrawString should be reserved for printing, and TextRenderer.DrawText should be used for all on-screen elements.



回答2:

How about something like:

private void Form1_Paint(object sender, PaintEventArgs e)
{
    using (Font normal = new Font("Tahoma", 10, FontStyle.Regular))
    using (Font bold = new Font("Tahoma", 10, FontStyle.Bold))
    using (StringFormat format = 
        (StringFormat)StringFormat.GenericTypographic.Clone())
    {
        format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces;
        Rectangle temp = ClientRectangle;

        DrawString(e.Graphics, SystemBrushes.WindowText, ref temp, format, "AB", normal);
        DrawString(e.Graphics, SystemBrushes.WindowText, ref temp, format, "CDE ", bold);
        DrawString(e.Graphics, SystemBrushes.WindowText, ref temp, format, "FG", normal);
    }
}

void DrawString(Graphics g, Brush brush, ref Rectangle rect, StringFormat format, string text, Font font)
{
    using (StringFormat copy = (StringFormat)format.Clone())
    {
        copy.SetMeasurableCharacterRanges(new CharacterRange[] {
        new CharacterRange(0, text.Length)});
        Region[] regions = g.MeasureCharacterRanges(text, font, rect, copy);

        g.DrawString(text, font, brush, rect, format);

        int width = (int)(regions[0].GetBounds(g).Width);
        rect.X += width;
        rect.Width -= width;
    }
}

Obtained from here.