Как вычислить правильную ширину цифры в пикселях? - PullRequest
0 голосов
/ 25 января 2019

У меня есть пользовательский элемент управления, который в будущем может иметь настраиваемый пользователем шрифт (масштабирование уже реализовано). Я должен заполнить прямоугольник двумя цифрами, которые образуют число base-10. У меня есть разные цвета для нуля, одной или обеих цифр.

со шрифтом {Name = Microsoft Sans Serif Size = 16} и следующими Graphics.MeasureString вызовами метода:

g.MeasureString("00", Font);
g.MeasureString("0", Font);

Я получаю:

  • Размер "00" равен {Ширина = 31.5486088 Высота = 26.8124962}
  • Размер "0" равен {Ширина = 19.3298588 Высота = 26.8124962}

Ширина "0" намного больше, чем половина ширины "00".

Я знаю о методах Graphics.MeasureString , у него много перегрузок, и я также знаю о классе StringFormat. Как правильно вычислить ширину символа '0'?

Поскольку шрифт будет настраиваться пользователем, я не хочу решать проблему, используя моноширинный шрифт.

Если я использую следующие звонки:

g.MeasureString("00", Font, 999, StringFormat.GenericTypographic);
g.MeasureString("0", Font, 999, StringFormat.GenericTypographic);

Ширина "0", по-видимому, равна половине ширины "00", но цифры перекрываются при рисовании с меньшим размером шрифта:

screenshot

Обновление: В методе OnPaint UserControl у меня есть этот код:

Graphics g = e.Graphics;

int[] indices = { 0, 1 };
CharacterRange[] charRanges = new CharacterRange[indices.Length];
for (int chx = 0; chx < indices.Length; ++chx)
{
    charRanges[chx] = new CharacterRange(indices[chx], 1);
}

StringFormat sf = new StringFormat(StringFormat.GenericDefault);
sf.SetMeasurableCharacterRanges(charRanges);

Region[] regions = e.Graphics.MeasureCharacterRanges("01", Font, e.ClipRectangle, sf);

RectangleF[] r = new RectangleF[regions.Length];
int i = 0;
foreach (Region rr in regions)
{
    r[i] = rr.GetBounds(g);
    g.DrawRectangle(Pens.Blue, r[i].X, r[i].Y, r[i].Width, r[i].Height);
    ++i;
}

g.DrawString("0", Font, Brushes.Black, r[0], sf);
g.DrawString("1", Font, Brushes.Black, r[1], sf);

шрифт {Name = "Microsoft Sans Serif" Size=25}. При запуске программы это то, что видно:

screenshot 2

Я хочу сделать цифры центрированными в синих прямоугольниках. Прямоугольники должны быть настолько большими, насколько это возможно в UserControl, но также должны оставлять место для процента от высоты UserControl. Шрифт должен адаптироваться к прямоугольникам.

1 Ответ

0 голосов
/ 19 февраля 2019

Небольшие корректировки необходимы, чтобы сделать эту работу, как предполагалось:

  1. TextRenderingHint.ClearTypeGridFit дает лучший результат при рендеринге текста.
    Он более точный и хорошо работает с сеткой Graphics.DrawString.
    См. Примечания, которые вы можете найти в ответе, связанном ниже, для получения дополнительной информации по этому вопросу.
  2. StringFormat выравнивание по горизонтали и вертикали.
  3. Модифицированный метод, позволяющий рисовать строки любой длины.
    Если строка больше контейнера, она будет перенесена с текущими настройками.
  4. Не имеет значения: Brush и Pen объявляются вне события Paint, чтобы разрешить их повторное определение при необходимости.

Различные реализации MeasureCharacterRanges здесь:
Как выделить обернутый текст в элементе управления

О Graphics.DrawString и TextRenderingHint.ClearTypeGridFit:
При рисовании длинной строки на растровом изображении возникают проблемы с рисованием


Шрифт 48em:
MeasureCharacterRanges 1

Шрифт 16em:
MeasureCharacterRanges 2

Шрифт 9em:
MeasureCharacterRanges 3

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);
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...