2016-10-05 3 views
1

У меня есть следующий код в проекте VisualStudio по умолчанию. Он передает DT_CALCRECT в DrawTextW, чтобы вычислить прямоугольник для рисования некоторого текста, затем он использует этот прямоугольник для рисования текста. Чтобы проверить это самостоятельно просто вставить этот код в проект в VisualStudio по умолчанию:DrawText с DT_CALCRECT и DT_RIGHT не работает

case WM_PAINT: 
    hdc = BeginPaint(hWnd, &ps); 
    // TODO: Add any drawing code here... 

    { 
     wchar_t txt[] = L"abcdef abcdef abcdef abcdef abcdef abcdef abcdef abcdef abcdef abcdef abcdef abcdef abcdef abcdef abcdef\r\nabc\r\n123456"; 
     BOOL useDT_RIGHT = TRUE; // <<< ** SWITCH THIS BETWEEN TRUE AND FALSE ** 
     wchar_t buf1[100] = {0}; 
     wchar_t buf2[100] = {0}; 
     RECT r1 = {0, 0, 192, 1000}; 
     RECT r2 = {r1.right + 10, r1.top, r1.right + 400, r1.top + 100}; 
     int ret1, ret2; 

     FillRect(hdc, &r1, (HBRUSH)GetStockObject(GRAY_BRUSH)); 

     ret1 = DrawTextW(hdc, txt, -1, &r1, 
      DT_CALCRECT | 
      DT_WORDBREAK | 
      (useDT_RIGHT == FALSE ? DT_LEFT : DT_RIGHT) 
     ); 
     if(ret1 == 0) MessageBoxW(NULL, L"ret1 == 0", NULL, MB_OK); 

     wsprintfW(buf1, L"useDT_RIGHT = %i\r\nDT_CALCRECT returned %i %i %i %i\r\nret1 = %i\r\n", useDT_RIGHT, r1.left, r1.top, r1.right, r1.bottom, ret1); 

     ret2 = DrawTextW(hdc, txt, -1, &r1, 
      DT_WORDBREAK | 
      (useDT_RIGHT == FALSE ? DT_LEFT : DT_RIGHT) 
     ); 
     if(ret2 == 0) MessageBoxW(NULL, L"ret2 == 0", NULL, MB_OK); 

     wsprintfW(buf2, L"%sret2 = %i", buf1, ret2); 
     DrawTextW(hdc, buf2, -1, &r2, DT_LEFT); 
    } 

    EndPaint(hWnd, &ps); 
    break; 

В коде, если useDT_RIGHT установлен в FALSE, текст выравнивается по левому краю и DT_CALCRECT возвращает правильный прямоугольник, как показано ниже:

http://i64.tinypic.com/2ptw2dk.png

Если useDT_RIGHT установлен в TRUE, текст выровнен по правому краю, но DT_CALCRECT возвращает неправильный прямоугольник, как показано ниже:

http://i68.tinypic.com/nwx9co.png

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

Документы для DT_CALCRECT говорят: «Если имеется несколько строк текста, DrawText использует ширину прямоугольника, на который указывает параметр lpRect, и расширяет базу прямоугольника, чтобы связать последнюю строку текста. Если самое большое слово чем ширина прямоугольника, ширина расширяется. Если текст меньше ширины прямоугольника, ширина уменьшается ».

Что бы я ожидал, так это то, что прямоугольник, возвращенный DrawTextW, будет правильным размером для рисования текста (в реальном коде прямоугольник также используется для позиционирования окружающих элементов управления, поэтому просто расширение его волей-неволей действительно помогают). Я также ожидал бы, что текст будет правильно выровнен (т. Е. Напротив текста, выровненного слева), а не беспорядок, как показано на втором скриншоте выше. При правильном выравнивание по правому краю, я имею в виду, как показано на этом скриншоте WordPad:

Http: //i63.tinypic.com/qqya1u.png (. Пожалуйста, удалите пространство по этой ссылке, чтобы заставить его работать)

Что не так с этим кодом? Почему DT_CALCRECT с DT_RIGHT не дает ожидаемых результатов? Или, если это так, почему второй вызов DrawTextW не выводит его правильно?

+0

Возможно ли, что есть пробелы в конце каждой строки на выровненном справа тексте, и поэтому ширина прямоугольника смещена? – VuVirt

+0

Я не уверен, что вы подразумеваете под смещением. В обоих случаях это один и тот же текст. Это тот же код работает в обоих случаях. Единственное различие между двумя скриншотами заключается в том, что используется DT_RIGHT и другой DT_LEFT. Тем не менее DrawText рисует правую выровненную. – Alice

+0

Нет, это не тот же текст. Левый выровненный на первом снимке экрана имеет дополнительный текст 123456. Я не уверен, что понимаю, какова ваша фактическая проблема. Можете ли вы объяснить, поскольку это не очевидно из скриншотов? – VuVirt

ответ

1

Похоже, что это поведение является ошибкой или по дизайну. Возможно, DT_WORDBREAK удаляет пробелы, и поэтому при использовании DT_RIGHT он создает более узкий прямоугольник. Во всяком случае, вот способ сделать DrawText вести себя так же, как при использовании DT_CALCRECT либо DT_LEFT или DT_RIGHT, вы можете проверить этот код (проверьте свой комментарий, который начинается с FIX):

case WM_PAINT: 
    hdc = BeginPaint(hWnd, &ps); 
    // TODO: Add any drawing code here... 

    { 
     wchar_t txt[] = L"abcdef abcdef abcdef abcdef abcdef abcdef abcdef abcdef abcdef abcdef abcdef abcdef abcdef abcdef abcdef\r\nabc\r\n123456"; 
     BOOL useDT_RIGHT = FALSE; // TRUE; // <<< ** SWITCH THIS BETWEEN TRUE AND FALSE ** 
     wchar_t buf1[100] = { 0 }; 
     wchar_t buf2[100] = { 0 }; 
     RECT r1 = { 0, 0, 192, 1000 }; 
     RECT r2 = { r1.right + 10, r1.top, r1.right + 400, r1.top + 100 }; 
     int ret1, ret2; 

     FillRect(hdc, &r1, (HBRUSH)GetStockObject(GRAY_BRUSH)); 

     ret1 = DrawTextW(hdc, txt, -1, &r1, 
      DT_CALCRECT | 
      DT_WORDBREAK | 
      (useDT_RIGHT == FALSE ? DT_LEFT : DT_RIGHT) 
      ); 
     if (ret1 == 0) MessageBoxW(NULL, L"ret1 == 0", NULL, MB_OK); 

     // FIX: The following two lines make DrawText with DT_CALCRECT behave the same way for DT_LEFT and DT_RIGHT 
     r1.right = 192; 
     r1.bottom = ret1; 

     wsprintfW(buf1, L"useDT_RIGHT = %i\r\nDT_CALCRECT returned %i %i %i %i\r\nret1 = %i\r\n", useDT_RIGHT, r1.left, r1.top, r1.right, r1.bottom, ret1); 

     ret2 = DrawTextW(hdc, txt, -1, &r1, 
      DT_WORDBREAK | 
      (useDT_RIGHT == FALSE ? DT_LEFT : DT_RIGHT) 
      ); 
     if (ret2 == 0) MessageBoxW(NULL, L"ret2 == 0", NULL, MB_OK); 

     wsprintfW(buf2, L"%sret2 = %i", buf1, ret2); 
     DrawTextW(hdc, buf2, -1, &r2, DT_LEFT); 
    } 

    EndPaint(hWnd, &ps); 
    break; 
+0

Фактически вторая строка «r1.bottom = ret1;» является избыточным, поскольку r1.bottom равно ret1 в любом случае, но я оставлю его для ясности. Идея состоит в том, чтобы сбросить ширину прямоугольника до исходного значения перед вызовом второго DrawText для визуализации текста. – VuVirt

+0

Это правильный ответ, потому что вы получаете как фактический размер прямоугольника, который DrawText извлекает обратно из DT_CALCRECT (0 0 184 96 в примере), а затем DrawText рисует текст, правильно выровненный по правому краю в этом прямоугольнике. Чтобы установить r1.right обратно до 192 перед вторым вызовом DrawText, а также тот факт, что первый вызов возвращает правильный прямоугольник, означает, что фактический рисунок выравнивания по правому краю будет неправильным. – Alice

+0

Это должна быть первая ошибка, которую я когда-либо видел в основной функции, которая, как представляется, не имеет абсолютно никаких ссылок в Интернете, указывающих ее (иначе я не использовал правильные условия поиска). Ошибка должна быть многолетней давности. Может быть, я первый человек, который когда-либо пытался выравнивать текст с помощью DrawText! – Alice

Смежные вопросы