2015-06-13 2 views
0

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

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

Как отрегулировать размер шрифта, чтобы строка могла поместиться внутри?

Я прочитал документы для GDI и ничего не нашел. Я до сих пор продолжаю искать в Интернете, в надежде найти что-то или получить представление о моей ...

GDI + вариант тоже ...

Следующий код размещен в ответ на комментарий от пользователя Jonathan Potter:

#include <windows.h> 
#include <windowsx.h> 
#include <CommCtrl.h> 
#include <stdio.h>  // swprintf_s() 
#include <math.h> 
#include <gdiplus.h> 
#include <string> 
using namespace Gdiplus; 

// enable Visual Styles 
#pragma comment(linker, "/manifestdependency:\"type='win32' \ 
         name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \ 
         processorArchitecture='*' publicKeyToken='6595b64144ccf1df' \ 
         language='*'\"") 

// link with Common Controls library 
#pragma comment(lib, "comctl32.lib") 
#pragma comment(lib, "GdiPlus.lib") 

//global variables 
HINSTANCE hInst; 

// main window procedure 
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
    switch (msg) 
    { 
    case WM_PAINT: 
    { 
     PAINTSTRUCT ps = { 0 }; 
     RECT rcClient = { 0 }; 
     HDC hdc = BeginPaint(hwnd, &ps); 

     GetClientRect(hwnd, &rcClient); 

     int pageWidth = rcClient.right - rcClient.left, 
      pageHeight = rcClient.bottom - rcClient.top; 

     HFONT font = NULL, oldFont = NULL; 

     // target rectangle, text should fit inside 
     Rectangle(hdc, 0, 0, pageWidth/4, pageHeight/10); 

     SIZE sz; 

     GetTextExtentPoint32(hdc, L"This is very long string that might not fit into specified rectangle", 
      lstrlen(L"This is very long string that might not fit into specified rectangle"), &sz); 

     if (sz.cx > (pageWidth/4)) 
     { 

      // get current font 
      LOGFONT lf; 
      GetObject(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf); 

      // scale it 
      lf.lfHeight = MulDiv(lf.lfHeight, (pageWidth/4), sz.cx); 

      font = CreateFontIndirect(&lf); 

      oldFont = SelectFont(hdc, font); 
     } 

     SetBkMode(hdc, TRANSPARENT); 
     SetTextColor(hdc, RGB(255, 0, 0)); 

     // draw text in test rectangle 
     RECT rcText = { 0 }; 

     rcText.left = 0; 
     rcText.top = 0; 
     rcText.right = pageWidth/4; 
     rcText.bottom = pageHeight/10; 

     DrawTextEx(hdc, 
      L"This is very long string that might not fit into specified rectangle", 
      wcslen(L"This is very long string that might not fit into specified rectangle"), 
      &rcText, DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_NOCLIP, NULL); 

     if (font != NULL) 
     { 
      SelectFont(hdc, oldFont); 
      DeleteFont(font); 
     } 

     EndPaint(hwnd, &ps); 
    } 
     return 0L; 
    case WM_SIZE: 
    { 
     InvalidateRect(hwnd, NULL, TRUE); 
    } 
     return 0L; 
    case WM_CLOSE: 
     ::DestroyWindow(hwnd); 
     return 0L; 
    case WM_DESTROY: 
    { 
     ::PostQuitMessage(0); 
    } 
     return 0L; 
    default: 
     return ::DefWindowProc(hwnd, msg, wParam, lParam); 
    } 
    return 0; 
} 

// WinMain 
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, 
    int nCmdShow) 
{ 
    // store hInstance in global variable for later use 
    hInst = hInstance; 

    WNDCLASSEX wc; 
    HWND hwnd; 
    MSG Msg; 

    // register main window class 
    wc.cbSize = sizeof(WNDCLASSEX); 
    wc.style = 0; 
    wc.lpfnWndProc = WndProc; 
    wc.cbClsExtra = 0; 
    wc.cbWndExtra = 0; 
    wc.hInstance = hInst; 
    wc.hIcon = LoadIcon(hInstance, IDI_APPLICATION); 
    wc.hCursor = LoadCursor(NULL, IDC_ARROW); 
    wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW); 
    wc.lpszMenuName = NULL; 
    wc.lpszClassName = L"Main_Window"; 
    wc.hIconSm = LoadIcon(hInstance, IDI_APPLICATION); 

    if (!RegisterClassEx(&wc)) 
    { 
     MessageBox(NULL, L"Window Registration Failed!", L"Error!", 
      MB_ICONEXCLAMATION | MB_OK); 

     return 0; 
    } 

    // initialize common controls 
    INITCOMMONCONTROLSEX iccex; 
    iccex.dwSize = sizeof(INITCOMMONCONTROLSEX); 
    iccex.dwICC = ICC_LISTVIEW_CLASSES | ICC_STANDARD_CLASSES; 
    InitCommonControlsEx(&iccex); 

    GdiplusStartupInput gdiplusStartupInput; 
    ULONG_PTR gdiplusToken; 
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); 

    // create main window 
    hwnd = CreateWindowEx(0, L"Main_Window", L"Autofit text inside rectangle", 
     WS_OVERLAPPEDWINDOW, 50, 50, 200, 200, NULL, NULL, hInstance, 0); 

    ShowWindow(hwnd, nCmdShow); 
    UpdateWindow(hwnd); 

    while (GetMessage(&Msg, NULL, 0, 0) > 0) 
    { 
     TranslateMessage(&Msg); 
     DispatchMessage(&Msg); 
    } 

    GdiplusShutdown(gdiplusToken); 
    return Msg.wParam; 
} 
+0

Регулировка размера шрифта на самом деле не очень хорошая идея. Фигуры рисования Windows API поддерживают обертывание и, как я помню, также «...» в конце слишком длинной строки (но, возможно, я ошибаюсь в последнем, может быть, это было только в названиях Windows). Если вы не хотите, чтобы это сокращение было обычным решением, это предоставить либо прокручивающую функциональность (используйте доступный для чтения, возможно, отключенный элемент управления редактирования), либо всплывающую подсказку или и то, и другое. Но, если вы действительно хотите, чтобы текст масштабировался, то я предлагаю рисовать его в растровом изображении в подходящем большом прямоугольнике, возможно, в два раза желаемого размера и масштабировать его. –

+0

Измерьте строку с текущим шрифтом (например, с помощью DrawRect (DT_CALCRECT) '), определите соотношение, по которому вам нужно масштабировать размер шрифта для подходящей строки. Например. если строка в настоящее время в два раза длиннее, вам нужен шрифт в два раза меньше. –

+0

* выяснить соотношение, по которому вам нужно масштабировать размер шрифта * Это не так просто. 'DrawTextEx' с' DT_CALCRECT' расширяет прямоугольник, когда строка не подходит, что делает мою жизнь труднее ... – AlwaysLearningNewStuff

ответ

1

Вы ищете DrawText:

int DrawText(_In_  HDC  hDC, 
      _Inout_ LPCTSTR lpchText, 
      _In_  int  nCount, 
      _Inout_ LPRECT lpRect, 
      _In_  UINT uFormat 
      ); 

Вы указываете прямоугольник, и он гарантирует, что текст не будет рисоваться вне этого прямоугольника. Он также имеет флаг DT_CALCRECT, если вам нужно вычислить прямоугольник на основе текста и текущего выбранного шрифта. Или вы можете использовать флаг DT_END_ELLIPSIS, DT_PATH_ELLIPSIS или DT_WORD_ELLIPSIS, чтобы обрезать чертеж текста с добавлением многоточия, чтобы пользователь мог видеть, когда текст длиннее прямоугольника.

+0

К сожалению, 'DrawTextEx' расширяет исходный прямоугольник, если текст не подходит, внимательно прочитайте документы о' DT_CALCRECT'. Именно то поведение, которое отключает меня, чтобы использовать этот API должным образом, я просто не знаю, как вычислить коэффициент масштабирования, который учитывает это поведение. – AlwaysLearningNewStuff

+1

@AlwaysLearningNewStuff. Могу ли я предложить, если возвращаемый прямоугольник больше желаемого, вы уменьшите размер шрифта и повторите попытку. Если существует огромный диапазон размеров шрифтов, используйте двоичный поиск, чтобы уменьшить количество шагов в поиске. Кроме того, поиск может определяться разницей между желаемым размером прямоугольника и возвращаемым размером прямоугольника. Например.если rect на 50% слишком большой, уменьшите размер шрифта на 50% и выполните поиск оттуда. Возможно, что Uniscribe может иметь решение более высокого уровня, я его не использовал. –

+0

@cardiffspaceman: Я слышал о Uniscribe, но никогда не использовал его. Я дам ваше другое предложение попробовать. Понять это сложно для меня, так как это моя первая попытка решить эту проблему. – AlwaysLearningNewStuff

0

Теоретически, что-то вроде этого должно работать, но я его не тестировал. Добавить соответствующую проверку ошибок и т. Д.

SIZE sz; 
GetTextExtentPoint32(hDC, pszMyString, lstrlen(pszMyString), &sz); 

if (sz.cx > iMyMaximumWidth) 
{ 
    // get current font 
    LOGFONT lf; 
    GetObject(GetCurrentObject(hDC, OBJ_FONT), sizeof(lf), &lf); 

    // scale it 
    lf.lfHeight = MulDiv(lf.lfHeight, iMyMaximumWidth, sz.cx); 
    HFONT hNewFont = CreateFontIndirect(&lf); 

    .. use hNewFont to render string, remember to delete it when done 
} 
+0

Я пробовал ваш фрагмент кода, но результат был не тем, который я ожидал. Текст не помещался внутри прямоугольника. Спасибо за попытку. Есть ли что-нибудь еще, что я могу сделать, чтобы помочь вам помочь? – AlwaysLearningNewStuff

+0

* О, этот метод будет работать только для текста в одной строке * Пробовал его с помощью одной строки, используя 'DrawTextEx' с' DT_SINGLELINE | DT_VCENTER | DT_NOCLIP', но это не удалось. Текст превышает правую границу прямоугольника. После изменения размера главного окна (я рисую в главном окне 'WM_PAINT') этот эффект сохраняется. Высота текста превышает нижнюю границу, при изменении размера окна до * чрезвычайно малого * размера ... – AlwaysLearningNewStuff

+0

* Таким образом, шрифт стал меньше * Нет, шрифт остался примерно таким же ... * но он все еще переполнен? * Да, по горизонтали. В крайнем случае, когда я уменьшаю окно до очень малых размеров, он также переполняется по вертикали ... – AlwaysLearningNewStuff

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