none
c#, визуально длина DrawString строки отличается от аналогичной в RichTextBox. RRS feed

  • Вопрос

  • Привет всем.

    Вступление

    Пишу контрол на подобие грида.
    Контрол содержит ряд ячеек. Активная ячейка отображается в RichTextBox, остальные ячейки рисуются при помощи DrawString. Дополнительное условие, фон должен быть моноширинным. (каждый символ имеет одинаковую длину).

    Проблема

    Возьмем моноширинный шрифт Curier New, 10.
    RichTextBox.Text = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
    ниже прям под ним нарисуем туже строку при помощи DrawString;
    Оказывается длинна строки RichTextBox визуально отличается от длинны DrawString.


    Выделить всёкод C#
    1:
    2:
    3:
    4:
    5:
    6:
    7:
    8:
    9:
    10:
    11:
    12:
    Font font = new Font("Courier New", 10);
     
    //для того чтобы рисовать моноширинным шрифтом.
    StringFormat stringFormat = System.Drawing.StringFormat.GenericTypographic;
    stringFormat.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces;
     
    //tb - (RichTextBox, границы отключены).
    tb.Font = font;
    tb.Text = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
     
    //Рисуем прям под ним
    e.Graphics.DrawString("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", font, Brushes.Black, 0, tb.Bounds.Height, stringFormat);



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

    Вопрос:

    Как сделать визуальную длину этих строк одинаковой, все зависимости от высоты моноширинного шрифта?

    Ломаю голову не первый день уже... 
    19 февраля 2011 г. 6:57

Ответы

  • Была в точности такая же проблема, заключается она в том, что в GDI+ длина строки расчитывается без учета сглаживания (посмотрите перечисление TextRenderingHint ). Для себя решил эту проблему полным отказом от GDI+ и использованием старого доброго GDI. Кроме того, скорость отрисовки увеличилась в 4 раза.

    На разных компьютерах по разному — это как раз настройки ClearType и особенности его работы в разных версиях Windows.

    • Помечено в качестве ответа Abolmasov Dmitry 20 февраля 2011 г. 16:04
    19 февраля 2011 г. 9:32
  • Все сделал!

    Кому интересно вот код.

     

     

    [DllImport("user32.dll", CharSet = CharSet.Unicode)]

    static extern int DrawText(IntPtr hdc, string lpStr, int nCount, ref Rect lpRect, int wFormat);

     

     

    [DllImport("Gdi32.dll")]

    private static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);

     

     

            private struct Rect

            {

                public int Left, Top, Right, Bottom;

                public Rect(Rectangle r)

                {

                    this.Left = r.Left;

                    this.Top = r.Top;

                    this.Bottom = r.Bottom;

                    this.Right = r.Right;

                }

            }

     

     

    private const int DT_SINGLELINE = 0x00000020;

    {

    Font font = new Font("Courier New", 10);

     

    IntPtr hfnt = font.ToHfont();

    IntPtr hdc = e.Graphics.GetHdc();

    SelectObject(hdc, hfnt);

    SizeF text_len = e.Graphics.MeasureString(l_text, Font, 0, stringFormat);

    Rect bounds = new Rect(new Rectangle(0, 0, text_len.Width, text_len.Height));

    string draw_text = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";

    int flags = DT_SINGLELINE;

    DrawText(hdc, draw_text, draw_text.Length, ref bounds, flags);

    e.Graphics.ReleaseHdc(hdc);

    }

     

    p.s. MeasureString тоже бы надо заменить на GDI.

     

    to Алексей Митев - Гиганское, человеческое спасибо!!!

     

    • Помечено в качестве ответа Abolmasov Dmitry 20 февраля 2011 г. 16:04
    19 февраля 2011 г. 11:07

Все ответы

  • Была в точности такая же проблема, заключается она в том, что в GDI+ длина строки расчитывается без учета сглаживания (посмотрите перечисление TextRenderingHint ). Для себя решил эту проблему полным отказом от GDI+ и использованием старого доброго GDI. Кроме того, скорость отрисовки увеличилась в 4 раза.

    На разных компьютерах по разному — это как раз настройки ClearType и особенности его работы в разных версиях Windows.

    • Помечено в качестве ответа Abolmasov Dmitry 20 февраля 2011 г. 16:04
    19 февраля 2011 г. 9:32
  • Спасибо за ответ.

    Попробовал поставить различные свойства TextRenderingHint объекту Graphics перед отрисовкой, проблема осталась...

    Старый добрый GDI это WinApi? Не очень в этом разбираюсь.

    Нашел функцию DrawText, но там в параметрах нет настройки фонта... Его как то отдельно надо задавать?

    Вообщем с помощью чего (каких функций/опций) отрисовать строку так, чтоб ее длинна визуально была такая же как в RichTextBox? (сейчас длинна короче)

    p.s. Может быть у вас будет примерчик)

    Заранее спасибо.

    19 февраля 2011 г. 10:22
  • Все сделал!

    Кому интересно вот код.

     

     

    [DllImport("user32.dll", CharSet = CharSet.Unicode)]

    static extern int DrawText(IntPtr hdc, string lpStr, int nCount, ref Rect lpRect, int wFormat);

     

     

    [DllImport("Gdi32.dll")]

    private static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);

     

     

            private struct Rect

            {

                public int Left, Top, Right, Bottom;

                public Rect(Rectangle r)

                {

                    this.Left = r.Left;

                    this.Top = r.Top;

                    this.Bottom = r.Bottom;

                    this.Right = r.Right;

                }

            }

     

     

    private const int DT_SINGLELINE = 0x00000020;

    {

    Font font = new Font("Courier New", 10);

     

    IntPtr hfnt = font.ToHfont();

    IntPtr hdc = e.Graphics.GetHdc();

    SelectObject(hdc, hfnt);

    SizeF text_len = e.Graphics.MeasureString(l_text, Font, 0, stringFormat);

    Rect bounds = new Rect(new Rectangle(0, 0, text_len.Width, text_len.Height));

    string draw_text = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";

    int flags = DT_SINGLELINE;

    DrawText(hdc, draw_text, draw_text.Length, ref bounds, flags);

    e.Graphics.ReleaseHdc(hdc);

    }

     

    p.s. MeasureString тоже бы надо заменить на GDI.

     

    to Алексей Митев - Гиганское, человеческое спасибо!!!

     

    • Помечено в качестве ответа Abolmasov Dmitry 20 февраля 2011 г. 16:04
    19 февраля 2011 г. 11:07
  • Пожалуйста, не забывайте отмечать ответ, спасибо.


    Для связи [mail]
    20 февраля 2011 г. 16:04