1

I specify a font and its size for my listview items using win32 api and it works properly in Windows Xp. I install it in Windows 7 and see size of fonts are too small and hard to read although i specified 17 for its size.

I increased default font sizes in Windows 7 but still the fonts in my program are too small.

This is the code that i specify font for the listview items inside Window procedure :

case WM_DRAWITEM:
        {

            LPDRAWITEMSTRUCT pDIS=(LPDRAWITEMSTRUCT)lParam;
            HDC hDC=pDIS -> hDC;
            RECT rc = pDIS -> rcItem;

            HBRUSH bg = (HBRUSH) (::GetStockObject(DC_BRUSH));
            HPEN pn=(HPEN)(::GetStockObject(NULL_PEN));
            ::SelectObject( hDC , bg );
            ::SelectObject( hDC , pn );
            ::SetTextColor( hDC , RGB(0,0,0));

            HFONT hF;
            hF=CreateFont(17, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, L"Tahoma");
            HFONT hOldFont = (HFONT) SelectObject(hDC, hF); 


            if( (pDIS->itemID % 2) != 0 )
                ::SetDCBrushColor(hDC, RGB(255,255,255));
            else{
                ::SetDCBrushColor(hDC, RGB(223, 241, 255));

            }
            ::Rectangle( hDC , rc.left , rc.top , rc.right , rc.bottom );

             char buffer[1000] = {0};
             ListView_GetItemText(pDIS -> hwndItem,  pDIS -> itemID, 0, (LPWSTR)buffer, 1000);


            ::DrawText(hDC, (LPWSTR)buffer, -1, &rc, DT_SINGLELINE | DT_VCENTER);
            SelectObject(hDC, hOldFont);
            DeleteObject(hF); 
        }
        break;

How can i make Windows display my desired font size and not that small font?

Thanks!

Code-Lover
  • 299
  • 1
  • 14
  • 2
    Use `SystemParametersInfo(SPI_GETNONCLIENTMETRICS...)` to find the default UI font: https://stackoverflow.com/a/49753232/4603670 - The default font in Windows 7 is Segoe UI, it's not available in XP. Ideally your application should be DPI aware and use larger font size when applicable, this matters for Windows 8 and 10. – Barmak Shemirani Sep 05 '19 at 15:01
  • 1
    17 is not a good size. You should do some calculations based on DPI. – Anders Sep 05 '19 at 15:05
  • 1
    Have you tried in Win10? I try to modify DPI or font size (17 - > 20) on my computer. It works. My environment is Windows 10. – Strive Sun Sep 06 '19 at 05:18
  • 1
    I seem to have found useful information about writing [high DPI Win32 applications](https://msdn.microsoft.com/en-us/windows/desktop/dd464659). I don't have Windows 7 to try this tutorial, but it's worth trying. – Strive Sun Sep 06 '19 at 05:48
  • 1
    Assuming that `HDC` is in `MM_TEXT` mapping mode (check that `GetMapMode` returns 1), font size is specified in pixels. Positive value means height without internal leading. Verify this by doing screenshot for letters 'Ty' - distance from top of 'T' to bottom of 'y' should be slightly less then 17. If it is, your Windows 7 machine could have denser DPI and font height needs to be adjusted by `MulDiv( reference_size, current_dpi, reference_dpi )`. – Daniel Sęk Sep 06 '19 at 06:37

1 Answers1

1

Use SystemParametersInfo to find the default font as follows:

NONCLIENTMETRICS metrics;
metrics.cbSize = sizeof(NONCLIENTMETRICS);
::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS),
        &metrics, 0);
hfont = CreateFontIndirect(&metrics.lfMessageFont);

Use .lfMessageFont for ListView and other child controls.

This will retrieve the correct font name and font size.

This font size is already adjusted for DPI settings of system and application.

You can create this font once during windows creation. Then assign it as the main font for the window and listview control. This will update the header control for the listview.

HFONT hfont;
...
case WM_CREATE:
{
    if (!hfont)
    {
        NONCLIENTMETRICS metrics;
        metrics.cbSize = sizeof(NONCLIENTMETRICS);
        ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS),
            &metrics, 0);
        hfont = CreateFontIndirect(&metrics.lfMessageFont);
    }
    hListView = CreateWindow(WC_LISTVIEW ...);
    SendMessage(hWnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0));
    SendMessage(hListView, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0));
    ...
    break;
}

Also, do not use (LPWSTR) cast to hide compiler warnings and errors. Use casting only when you are sure it's applicable. In this case, char and wchar_t are very different storage types, casting may in some special cases, but it's far from reliable.

char buffer[1000] creates a buffer of size 1000 bytes. But you are making a call to ListView_GetItemText to read 1000 Unicode characters, which in this case is 2000 bytes and results in buffer overrun. You can change as follows:

case WM_DRAWITEM:
{
    LPDRAWITEMSTRUCT pDIS = (LPDRAWITEMSTRUCT)lParam;
    HDC hDC = pDIS->hDC;
    RECT rc = pDIS->rcItem;

    COLORREF textcolor = RGB(0, 0, 0);
    COLORREF bkcolor = RGB(255, 255, 255);
    if((pDIS->itemID % 2) == 0)
    {
        bkcolor = RGB(223, 241, 255);
    }
    if(pDIS->itemState & ODS_SELECTED)
    {
        textcolor = RGB(255, 255, 255);
        bkcolor = RGB(0, 0, 255);
    }

    SetDCBrushColor(hDC, bkcolor);
    SelectObject(hDC, GetStockObject(DC_BRUSH));
    SelectObject(hDC, GetStockObject(NULL_PEN));
    SetTextColor(hDC, textcolor);

    Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);

    auto oldfont = SelectObject(hDC, hfont);
    wchar_t buffer[1000] = { 0 };
    ListView_GetItemText(pDIS->hwndItem, pDIS->itemID, 0, buffer, 1000);
    DrawText(hDC, buffer, -1, &rc, DT_SINGLELINE | DT_VCENTER);
    SelectObject(hDC, oldfont);

    return TRUE;
}

*hfont is not destroyed in above window procedure. It should be cleaned up elsewhere.

Barmak Shemirani
  • 30,904
  • 6
  • 40
  • 77