How to compute the correct width of a digit in pixels?

后端 未结 1 1766
梦毁少年i
梦毁少年i 2021-01-21 23:02

I have a custom control that may have user customizable Font in future (the zoom is already implemented). I must fill a rectangle under two digits that form a base-10 number. I

相关标签:
1条回答
  • 2021-01-21 23:42

    Small adjustments are required to make this work as intended:

    1. TextRenderingHint.ClearTypeGridFit gives a better result when rendering the Text.
      It's more precise and works well with the grid-fitting nature of Graphics.DrawString.
      See the notes you can find in the answer linked below for more informations on this matter.
    2. StringFormat alignment in both horizontal and vertical dimensions.
    3. A modified method that allows to draw strings of any length.
      If the string is larger than the container, it will be wrapped, with the current settings.
    4. Irrelevant: Brush and Pen are declared outside the Paint event, to allow their re-definition when required.

    Different implementations of MeasureCharacterRanges here:
    How to highlight wrapped text in a control

    About Graphics.DrawString and TextRenderingHint.ClearTypeGridFit:
    Drawing a Long String on to a Bitmap results in Drawing Issues


    Font 48em:

    Font 16em:

    Font 9em:

    Pen pen = new Pen(Color.LightGreen, 1);
    Brush brush = new SolidBrush(Color.White);
    string sourceDigits = "010011001";
    
    private void panel1_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
    
        CharacterRange[] charRanges = new CharacterRange[sourceDigits.Length];
        for (int chx = 0; chx < sourceDigits.Length; ++chx) {
            charRanges[chx] = new CharacterRange(chx, 1);
        }
    
        using (StringFormat sf = new StringFormat())
        {
            sf.Alignment = StringAlignment.Center;
            sf.LineAlignment = StringAlignment.Center;
            sf.SetMeasurableCharacterRanges(charRanges);
    
            Region[] regions = e.Graphics.MeasureCharacterRanges(sourceDigits, Font, e.ClipRectangle, sf);
            for (int i = 0; i < regions.Length; i++) {
                RectangleF rect = regions[i].GetBounds(e.Graphics);
                e.Graphics.DrawRectangle(pen, rect.X, rect.Y, rect.Width, rect.Height);
                e.Graphics.DrawString(char.ToString(sourceDigits[i]), Font, brush, rect, sf);
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题