2

Trying to vertically center/align the text in an edit control (Win32 API, pure C, no MFC) but with no luck. Tried solutions from other answers such as this one or this and other quite old forums around, but no luck:

enter image description here

I could reduce the height of the control, but this is just a workaround. I don't want to make it multi-line. Code to create the control:

CreateWindowW(L"Edit", NULL,
    WS_CHILD | WS_VISIBLE | WS_BORDER,
    MulDiv(LOWORD(units),  50, 4), 0,
    MulDiv(LOWORD(units), 150, 4),
    MulDiv(HIWORD(units),  14, 8),
    hwnd, NULL, NULL, NULL);

Question: is there really no way to vertically align the text?

Ken White
  • 123,280
  • 14
  • 225
  • 444
evilmandarine
  • 4,241
  • 4
  • 17
  • 40
  • 4
    Not directly, but you can emulate it by subclassing the edit control and handling `WM_NCCALCSIZE`. https://www.codeguru.com/cpp/v-s/devstudio_macros/textoperations/article.php/c8491/Vertical-Text-Centering-in-an-Edit-Control.htm For multiline edit control you could use `EM_SETRECT`. – zett42 Aug 29 '19 at 20:53
  • @zett42 Thank you. Saw a similar post but that's C++, I'm looking for a C solution. – evilmandarine Aug 29 '19 at 20:57
  • 3
    @supafly using pure Win32 API, what works in C++ will also work in C, since the Win32 API is a C based API. – Remy Lebeau Aug 29 '19 at 22:00
  • @RemyLebeau Ok, but I don't understand how to use that C++ class in a C program. Should I still use CreateWindowW somehow? Most WinAPI samples I come accross are 100% C++. For a C# programmer, this is a bit obscure. – evilmandarine Aug 30 '19 at 08:53
  • 3
    @supafly "*I don't understand how to use that C++ class in a C program*" - you can't use a C++ class in C, unless you wrap it in a C interface, such as in a DLL. But you can make the same Win32 API calls in C that the C++ class makes. "*Should I still use CreateWindowW somehow?*" - yes. "*Most WinAPI samples I come accross are 100% C++*" - only if you are looking at samples for C++ based frameworks like MFC, Qt, etc. Look at C based samples instead. Plenty of them around. Even Microsoft's documented samples are written with C in mind, since again, the Win32 API is a C based API. – Remy Lebeau Aug 30 '19 at 14:42
  • @zett42 Using [`EM_SETRECT`](https://docs.microsoft.com/en-us/windows/win32/controls/em-setrect) actually works. If we add `ES_MULTILINE` style to a single line edit control, we can clip its drawing rectangle. On default system font, raw texts take up 16px(?) height with 2px borders over and below it, so we should consider it 20px high. If your edit control is e.g 30px high, just clip it from above for 5px and it's vertically centered perfectly. To do this, we need to obtain its `RECT` by `GetWindowRect` function and offset it like `OffsetRect(&rc,-rc.left,-rc.top);` first and we're good to go – user814412 Jan 24 '21 at 09:58

1 Answers1

2

Use WS_BORDER-style to turn the vertical align on. If you want to avoid a border-box, you should subclassing the control by SetWindowLongPtr and redraw the border in WM_PAINT.

HWND hEdit = CreateWindow(WC_EDIT, NULL, ES_CENTER | ES_AUTOHSCROLL | WS_VISIBLE | WS_CHILD | WS_BORDER, 0, 0, 0, 0, hWnd, (HMENU)IDC_EDIT, GetModuleHandle(0), NULL);
SetProp(hEdit, TEXT("WNDPROC"), (HANDLE)SetWindowLongPtr(hEdit, GWLP_WNDPROC, (LONG_PTR)cbNewEdit));
...
LRESULT CALLBACK cbNewFilterEdit(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    WNDPROC cbDefault = (WNDPROC)GetProp(hWnd, TEXT("WNDPROC"));
            
    switch(msg) {
        // Overwrite black border
        case WM_PAINT:
        case WM_NCPAINT: {
            cbDefault(hWnd, msg, wParam, lParam);
            
            RECT rc;
            GetWindowRect(hWnd, &rc);
            OffsetRect(&rc, -rc.left, -rc.top);
            HDC hDC = GetWindowDC(hWnd);
            HPEN hPen = CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
            HPEN oldPen = SelectObject(hDC, hPen);
            SelectObject(hDC, GetStockObject(NULL_BRUSH));
            Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
            SelectObject(hDC, oldPen);
            DeleteObject(oldPen);
            ReleaseDC(hWnd, hDC);
            return 0;
        }
        break;  
    
        ...

        case WM_DESTROY: {
            RemoveProp(hWnd, TEXT("WNDPROC"));
        }
        break;
    }

    return CallWindowProc(cbDefault, hWnd, msg, wParam, lParam);
}
Aikon Mogwai
  • 4,954
  • 2
  • 18
  • 31