RichEdit Vertical Text Aligment
How can i align the text in a TRichEdit vertically centered. There is a property for aligning paragaph by horizontal but there isn't any property 开发者_C百科for vertical alignment. I use C++ builder.
TRichEdit is just a wrapper around MS RichEdit component, so you can get a handle and use WinAPI to work with it directly: http://msdn.microsoft.com/en-us/library/bb787873(VS.85).aspx
The Richedit interface does not have a method for this. However it is fairly straightforward to do it using existing messages. Use EM_POSFROMCHAR to get the vertical position of the first and last character in the control, adding the height of the last character. Then calculate the offset from the top of the control needed to centre the text vertically. Then use an EM_SETRECT message to adjust the position that the txt is drawn in the control.
If you want to do this dynamically as the text is modified you will need to subclass the control and handle the appropriate messages. See the code snippets below.
// 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 ) );
}
精彩评论