RichEdit Вертикальный текст Aligment
Как я могу выровнять текст в TRichEdit вертикально по центру. Существует свойство для выравнивания парагафа по горизонтали, но нет свойства для вертикального выравнивания. Я использую C++ Builder.
1 ответ
TRichEdit - это просто оболочка для компонента MS RichEdit, поэтому вы можете получить дескриптор и использовать WinAPI для работы с ним напрямую: http://msdn.microsoft.com/en-us/library/bb787873(VS.85).aspx
В интерфейсе Richedit для этого нет метода. Однако это довольно просто сделать, используя существующие сообщения. Используйте EM_POSFROMCHAR, чтобы получить вертикальное положение первого и последнего символа в элементе управления, добавив высоту последнего символа. Затем вычислите смещение от верха элемента управления, необходимое для центрирования текста по вертикали. Затем используйте сообщение EM_SETRECT, чтобы настроить положение, в котором текст отображается в элементе управления.
Если вы хотите сделать это динамически по мере изменения текста, вам нужно будет создать подкласс элемента управления и обработать соответствующие сообщения. См. Фрагменты кода ниже.
// in WM_CREATE of parent window or when control is created
hwndTextbox = CreateWindowEx (0, MSFTEDIT_CLASS, (WCHAR*)yourtext,
ES_MULTILINE | WS_VISIBLE | WS_SIZEBOX | WS_CHILD | WS_CLIPSIBLINGS,
left, top, width, height,
hwnd, NULL, hInst, NULL);
SetProp (hwndTextbox, L"oldproc", (HANDLE)(ULONG_PTR)GetWindowLong (hwndTextbox, GWL_WNDPROC));
SetWindowLong (hwndTextbox, GWL_WNDPROC, (DWORD)(LRESULT)RicheditWndProc);
// after control has been drawn eg in WM_SIZE of parent window
{
RECT rclBox;
SendMessage(hwndTextbox, EM_GETRECT, 0, (LPARAM)&rclBox);
rclBox.top = vertoffset; // previously saved vertical offset for control either globally or as window property of control
SendMessage(hwndTextbox, EM_SETRECT, 0, (LPARAM)&rclBox);
InvalidateRect(hwndTextbox, NULL, TRUE);
}
LRESULT WINAPI RicheditWndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
static BOOL fVcentre; // will need to be stored as a window property if more than one control
WNDPROC lpOldProc;
CHARFORMAT cf;
lpOldProc = (WNDPROC)GetProp( hwnd, L"oldproc" );
switch( msg )
{
case WM_TIMER:
// use timer to ensure text is redrawn before positioning
switch(wParam)
{
case 1:
KillTimer(hwnd, 1);
{
POINTL pt, pt1;
RECT rcl;
RECT rclParent;
int last, height=0, offset, current;
SendMessage (hwnd, EM_GETSEL, (WPARAM)¤t, 0);
SendMessage(hwnd, EM_GETRECT, 0, (LPARAM)&rcl);
GetClientRect(GetParent(hwnd), &rclParent);
SendMessage (hwnd, EM_SETSEL, 0, -1);
SendMessage (hwnd, EM_GETSEL, 0, (LPARAM)&last);
SendMessage(hwnd, EM_POSFROMCHAR, (WPARAM)&pt, 0);
SendMessage(hwnd, EM_POSFROMCHAR, (WPARAM)&pt1, last);
// get height of last character
SendMessage (hwnd, EM_SETSEL, last-1, last);
memset(&cf, 0, sizeof cf);
cf.cbSize = sizeof cf;
SendMessage (hwnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
if(cf.dwMask & CFM_SIZE)
height = cf.yHeight/15;
height = height + pt1.y - pt.y;
vertoffset = (rcl.bottom - height)/2;
ifvertoffset > 0) // vertoffset can be < 0 if needed
{
rcl.top = vertoffset;
SendMessage(hwnd, EM_SETRECT, 0, (LPARAM)&rcl);
InvalidateRect(hwnd, NULL, TRUE);
}
SendMessage (hwnd, EM_SETSEL, current, current);
}
break;
}
break;
case WM_DESTROY: // Put back old window proc and
SetWindowLong( hwnd, GWL_WNDPROC, (DWORD)(LRESULT)lpOldProc );
RemoveProp( hwnd, L"oldproc" ); // remove window property
break;
case WM_KEYUP:
case WM_CHAR:
case WM_PASTE:
case WM_CUT:
case EM_UNDO:
case EM_REDO:
// any message that modifies the text
if(fVcentre)
SetTimer(hwnd, 1, 100, NULL);
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_TFVCENTRE: // id to centre text
{
POINTL pt, pt1;
RECT rcl;
RECT rclParent;
int last, height=0, offset, current;
fVcentre = !fVcentre;
SendMessage(hwnd, EM_GETRECT, 0, (LPARAM)&rcl);
if(fVcentre)
{
GetClientRect(GetParent(hwnd), &rclParent);
SendMessage (hwnd, EM_GETSEL, (WPARAM)¤t, 0);
SendMessage (hwnd, EM_SETSEL, 0, -1);
SendMessage (hwnd, EM_GETSEL, 0, (LPARAM)&last);
SendMessage(hwnd, EM_POSFROMCHAR, (WPARAM)&pt, 0);
SendMessage(hwnd, EM_POSFROMCHAR, (WPARAM)&pt1, last);
// get height of last character
SendMessage (hwnd, EM_SETSEL, last-1, last);
memset(&cf, 0, sizeof cf);
cf.cbSize = sizeof cf;
SendMessage (hwnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
if(cf.dwMask & CFM_SIZE)
height = cf.yHeight/15;
height = height + pt1.y - pt.y;
vertoffset = (rcl.bottom - height)/2;
ifvertoffset > 0)
{
rcl.top = vertoffset
SendMessage(hwnd, EM_SETRECT, 0, (LPARAM)&rcl);
InvalidateRect(hwnd, NULL, TRUE);
}
SendMessage (hwnd, EM_SETSEL, current, current);
}
else
{
rcl.top = 0;
vertoffset = 0;
SendMessage(hwnd, EM_SETRECT, 0, (LPARAM)&rcl);
InvalidateRect(hwnd, NULL, TRUE);
}
}
break;
}
break;
} // Pass all non-custom messages to old window proc
return( CallWindowProc( lpOldProc, hwnd, msg, wParam, lParam ) );
}