Центр вывода текста из 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классом.

11.08.2008 17:37:57
6 ОТВЕТОВ

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

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

3
21.04.2015 13:03:21

Вот код Это предполагает, что вы делаете это на форме или 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 (то есть, вы ее не используете) - вот что доставляет вам трудности.

2
11.08.2008 17:50:41

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

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)
10
11.08.2008 18:30:09
спасибо, что показали другой способ рисовать вещи, которые действительно помогают мне с проблемой выравнивания по центру. Оказывается, TextRenderer.DrawText точнее, чем простая e.graphics.drawstring, большое спасибо, проголосуйте за меня :)
user3061078 3.02.2015 12:55:53
РЕШЕНИЕ

Благодаря сочетанию полученных предложений я пришел к следующему:

    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 (), чтобы я не вызывал его каждый раз, когда рисую букву. Его нужно вызывать только при изменении размера элемента управления. Я просто включил его в функцию для полноты.

19
11.08.2008 19:03:59

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

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

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

82
9.10.2017 15:39:34

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

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

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

58
24.09.2011 17:44:35
Решение Криса великолепно. Кстати, если вы хотите установить в центре по горизонтали, но по вертикали в любом положении: e.Graphics.DrawString («Моя строка», this.Font, Brushes.Black, e.CellBounds.Width / 2, y, sf); // у вертикальное положение
camino 27.01.2017 13:55:03
Я использовал graphics.VisibleClipBounds.Width / 2, потому что не смог найти свойство .CellBounds, и оно работало довольно хорошо.
Olorunfemi Ajibulu 10.10.2019 14:26:17