Центрировать вывод текста из Graphics.DrawString ()

Я использую класс .NETCF (Windows Mobile) Graphics и метод DrawString() для отображения одного символа на экране.

Проблема в том, что я не могу правильно отцентрировать его. Независимо от того, что я установил для координаты Y места рендеринга строки, он всегда оказывается ниже этого значения, и чем больше размер текста, тем больше смещение по оси Y.

Например, при размере текста 12 смещение составляет около 4, а при размере 32 смещение составляет около 10.

Я хочу, чтобы персонаж по вертикали занимал большую часть прямоугольника, в котором он рисуется, и располагался по центру по горизонтали. Вот мой основной код. this ссылается на пользовательский элемент управления, в котором он нарисован.

Graphics g = this.CreateGraphics();

float padx = ((float)this.Size.Width) * (0.05F);
float pady = ((float)this.Size.Height) * (0.05F);

float width = ((float)this.Size.Width) - 2 * padx;
float height = ((float)this.Size.Height) - 2 * pady;

float emSize = height;

g.DrawString(letter, new Font(FontFamily.GenericSansSerif, emSize, FontStyle.Regular),
            new SolidBrush(Color.Black), padx, pady);

Да, я знаю, что есть элемент управления меткой, который я мог бы использовать вместо этого и с его помощью установить центрирование, но мне действительно нужно сделать это вручную с помощью класса Graphics.


person Adam Haile    schedule 11.08.2008    source источник


Ответы (6)


Я хочу еще раз проголосовать за объект StringFormat. Вы можете использовать это просто, чтобы указать «центр, центр», и текст будет нарисован по центру в прямоугольнике или точках:

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

Однако в CF есть одна проблема. Если вы используете Center для обоих значений, он отключает TextWrapping. Понятия не имею, почему это происходит, похоже, это ошибка CF.

person Quibblesome    schedule 25.08.2008

Для выравнивания текста используйте следующее:

StringFormat sf = new StringFormat();
sf.LineAlignment = StringAlignment.Center;
sf.Alignment = StringAlignment.Center;
e.Graphics.DrawString("My String", this.Font, Brushes.Black, ClientRectangle, sf);

Обратите внимание, что текст здесь выровнен по заданным границам. В этом примере это ClientRectangle.

person Chris Hughes    schedule 13.10.2008
comment
Решение Криса отличное. Кстати, если вы хотите установить в центре по горизонтали, но по вертикали в любом положении: e.Graphics.DrawString (My String, this.Font, Brushes.Black, e.CellBounds.Width / 2, y, sf); // y - вертикальное положение - person camino; 27.01.2017
comment
Я использовал graphics.VisibleClipBounds.Width / 2, потому что мне не удалось найти свойство .CellBounds, и оно работало достаточно хорошо. - person Olorunfemi Ajibulu; 10.10.2019

Комбинируя полученные предложения, я пришел к следующему:

    private void DrawLetter()
    {
        Graphics g = this.CreateGraphics();

        float width = ((float)this.ClientRectangle.Width);
        float height = ((float)this.ClientRectangle.Width);

        float emSize = height;

        Font font = new Font(FontFamily.GenericSansSerif, emSize, FontStyle.Regular);

        font = FindBestFitFont(g, letter.ToString(), font, this.ClientRectangle.Size);

        SizeF size = g.MeasureString(letter.ToString(), font);
        g.DrawString(letter, font, new SolidBrush(Color.Black), (width-size.Width)/2, 0);

    }

    private Font FindBestFitFont(Graphics g, String text, Font font, Size proposedSize)
    {
        // Compute actual size, shrink if needed
        while (true)
        {
            SizeF size = g.MeasureString(text, font);

            // It fits, back out
            if (size.Height <= proposedSize.Height &&
                 size.Width <= proposedSize.Width) { return font; }

            // Try a smaller font (90% of old size)
            Font oldFont = font;
            font = new Font(font.Name, (float)(font.Size * .9), font.Style);
            oldFont.Dispose();
        }
    }

Пока это работает безупречно.

Единственное, что я бы изменил, - это переместить вызов FindBestFitFont () в событие OnResize (), чтобы я не вызывала его каждый раз, когда рисую букву. Его нужно вызывать только при изменении размера элемента управления. Я просто включил его в функцию для полноты картины.

person Adam Haile    schedule 11.08.2008

Чтобы нарисовать текст по центру:

TextRenderer.DrawText(g, "my text", Font, Bounds, ForeColor, BackColor, 
  TextFormatFlags.HorizontalCenter | 
  TextFormatFlags.VerticalCenter |
  TextFormatFlags.GlyphOverhangPadding);

Определить оптимальный размер шрифта для заполнения области немного сложнее. Я обнаружил, что одна рабочая душа - это метод проб и ошибок: начните с большого шрифта, затем несколько раз измерьте строку и сожмите шрифт до тех пор, пока он не подойдет.

Font FindBestFitFont(Graphics g, String text, Font font, 
  Size proposedSize, TextFormatFlags flags)
{ 
  // Compute actual size, shrink if needed
  while (true)
  {
    Size size = TextRenderer.MeasureText(g, text, font, proposedSize, flags);

    // It fits, back out
    if ( size.Height <= proposedSize.Height && 
         size.Width <= proposedSize.Width) { return font; }

    // Try a smaller font (90% of old size)
    Font oldFont = font;
    font = new Font(font.FontFamily, (float)(font.Size * .9)); 
    oldFont.Dispose();
  }
}

Вы бы использовали это как:

Font bestFitFont = FindBestFitFont(g, text, someBigFont, sizeToFitIn, flags);
// Then do your drawing using the bestFitFont
// Don't forget to dispose the font (if/when needed)
person dbkk    schedule 11.08.2008
comment
спасибо, что показали другой способ рисования, это действительно помогло мне с проблемой выравнивания по центру, оказывается, TextRenderer.DrawText более точен, чем простой e.graphics.drawstring, большое спасибо, голосуйте от меня :) - person ; 03.02.2015

Вот код. Предполагается, что вы делаете это в форме или в UserControl.

Graphics g = this.CreateGraphics();
SizeF size = g.MeasureString("string to measure");

int nLeft = Convert.ToInt32((this.ClientRectangle.Width / 2) - (size.Width / 2));
int nTop = Convert.ToInt32((this.ClientRectangle.Height / 2) - (size.Height / 2));

Из вашего сообщения похоже, что часть ClientRectangle (например, вы ее не используете) - это то, что вызывает у вас трудности.

person TheSmurf    schedule 11.08.2008

Вы можете использовать экземпляр объекта StringFormat, переданный в метод DrawString, для центрирования текста.

См. метод Graphics.DrawString и Класс StringFormat.

person John    schedule 11.08.2008