Win32滚动条剪辑文本

Win32 Scrollbar clips text

本文关键字:文本 滚动条 Win32      更新时间:2023-10-16

当我调整窗口大小然后使用边框时,文本被剪切。当我再次调整窗口大小时,剪切的文本再次正确显示。

为什么会发生这种情况,我该如何预防?

截图:https://i.stack.imgur.com/0FkHU.png

main.cpp:

#include <Windows.h>
#include "sysmets.h"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, PSTR szCmdLine, int iCmdShow)
{
    static TCHAR szAppName[] = TEXT("Scratch");
    HWND hwnd;
    MSG msg;
    WNDCLASS wndclass;
    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.lpfnWndProc = WndProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hInstance;
    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndclass.lpszMenuName = NULL;
    wndclass.lpszClassName = szAppName;
    if(!RegisterClass(&wndclass))
    {
        MessageBox(NULL, TEXT("Program requires Windows NT!"), szAppName, MB_ICONERROR);
        return 0;
    }
    hwnd = CreateWindow(szAppName, TEXT("Scratch"),
                        WS_OVERLAPPEDWINDOW | WS_VSCROLL,
                        CW_USEDEFAULT, CW_USEDEFAULT,
                        CW_USEDEFAULT, CW_USEDEFAULT,
                        NULL, NULL, hInstance, NULL);
    ShowWindow(hwnd, iCmdShow);
    UpdateWindow(hwnd);
    while(GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    TEXTMETRIC tm;
    PAINTSTRUCT ps;
    SCROLLINFO si;
    static int cxChar, cyChar, cxClient, cyClient, cxCaps;
    int i, y, iPaintBeg, iPaintEnd, iVertPos;
    TCHAR buffer[10];
    switch(message)
    {
    case WM_CREATE:
        hdc = GetDC(hwnd);
        GetTextMetrics(hdc, &tm);
        cxChar = tm.tmAveCharWidth;
        cyChar = tm.tmHeight + tm.tmExternalLeading;
        cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2;
        ReleaseDC(hwnd, hdc);
        return 0;
    case WM_SIZE:
        cxClient = LOWORD(lParam);
        cyClient = HIWORD(lParam);
        si.cbSize = sizeof(SCROLLINFO);
        si.fMask = SIF_PAGE | SIF_RANGE;
        si.nMin = 0;
        si.nMax = NUMLINES - 1;
        si.nPage = cyClient / cyChar;
        SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
        return 0;
    case WM_PAINT:
        hdc = BeginPaint(hwnd, &ps);
        si.cbSize = sizeof(SCROLLINFO);
        si.fMask = SIF_POS;
        GetScrollInfo(hwnd, SB_VERT, &si);
        iVertPos = si.nPos;
        iPaintBeg = max(0, iVertPos + ps.rcPaint.top / cyChar);
        iPaintEnd = min(NUMLINES - 1, iVertPos + ps.rcPaint.bottom / cyChar);

        for (i = iPaintBeg; i < iPaintEnd; i++)
        {
            y = cyChar * (i - iVertPos);
            TextOut(hdc, 0, y, sysmetrics[i].szLabel, lstrlen(sysmetrics[i].szLabel));
            TextOut(hdc, 22 * cxCaps, y, sysmetrics[i].szDesc, lstrlen(sysmetrics[i].szDesc));
            SetTextAlign(hdc, TA_TOP | TA_RIGHT);
            TextOut(hdc, 60 * cxCaps, y, buffer, wsprintf(buffer, TEXT("%5d") ,GetSystemMetrics(sysmetrics[i].iIndex)));
            SetTextAlign(hdc, TA_TOP | TA_LEFT);
        }
        EndPaint(hwnd, &ps);
        return 0;
    case WM_VSCROLL:
        si.cbSize = sizeof(SCROLLINFO);
        si.fMask = SIF_ALL;
        GetScrollInfo(hwnd, SB_VERT, &si);
        iVertPos = si.nPos;
        switch (LOWORD(wParam))
        {
        case SB_LINEUP:
            si.nPos -= 1;
            break;
        case SB_LINEDOWN:
            si.nPos += 1;
            break;
        case SB_PAGEUP:
            si.nPos -= si.nPage;
            break;
        case SB_PAGEDOWN:
            si.nPos += si.nPage;
            break;
        case SB_THUMBTRACK:
            si.nPos = si.nTrackPos;
            break;
        default:
            break;
        }
        SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
        GetScrollInfo(hwnd, SB_VERT, &si);
        if(iVertPos != si.nPos)
        {
            ScrollWindow(hwnd, 0, cyChar * (iVertPos - si.nPos), NULL, NULL);
        }
        UpdateWindow(hwnd);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

sysmets.h(定义NUMLINES和sysmetrics结构)

#ifndef SYSMETS_H_
#define SYSMETS_H_
#include <windows.h>
#define NUMLINES ((int) sizeof(sysmetrics) / sizeof(sysmetrics[0]))
struct
{
    int iIndex;
    TCHAR *szLabel;
    TCHAR *szDesc;
}
sysmetrics [] = 
{
    SM_CXSCREEN, TEXT("SM_CXSCREEN"), TEXT("Screen Width in pixels."),
    SM_CYSCREEN, TEXT("SM_CYSCREEN"), TEXT("Screen Height in pixels."),
    SM_CXVSCROLL, TEXT("SM_CXVSCROLL"), TEXT("Vertical Scroll Width"),
    SM_CYHSCROLL, TEXT("SM_CYHSCROLL"), TEXT("Horizontal Scroll Height"),
    SM_CYCAPTION, TEXT("SM_CYCAPTION"), TEXT("Caption Bar Height"),
    SM_CXBORDER, TEXT("SM_CXBORDER"), TEXT("Window Border Width"),
    SM_CYBORDER, TEXT("SM_CYBORDER"), TEXT("Window Border Height"),
    SM_CXFIXEDFRAME, TEXT("SM_CXFIXEDFRAME"), TEXT("Dialog Window Frame Width"),
    SM_CYFIXEDFRAME, TEXT("SM_CYFIXEDFRAME"), TEXT("Dialog Window Frame Height"),
    SM_CYVTHUMB, TEXT("SM_CYVTHUMB"), TEXT("Vertical scroll thumb height"),
    SM_CXHTHUMB, TEXT("SM_CXHTHUMB"), TEXT("Horizontal scroll thumb width"),
    SM_CXICON, TEXT("SM_CXICON"), TEXT("Icon width"),
    SM_CYICON, TEXT("SM_CYICON"), TEXT("Icon height"),
    SM_CXCURSOR, TEXT("SM_CXCURSOR"), TEXT("Cursor width"),
    SM_CYCURSOR, TEXT("SM_CYCURSOR"),TEXT("Cursor height"),
    SM_CYMENU, TEXT("SM_CYMENU"), TEXT("Menu bar height"),
    SM_CXFULLSCREEN, TEXT("SM_CXFULLSCREEN"), TEXT("Full screen client area width"),
    SM_CYFULLSCREEN, TEXT("SM_CYFULLSCREEN"), TEXT("Full screen client area height"),
    SM_CYKANJIWINDOW, TEXT("SM_CYKANJIWINDOW"), TEXT("Kanji window height"),
    SM_MOUSEPRESENT, TEXT("SM_MOUSEPRESENT"), TEXT("Mouse present flag"),
    SM_CYVSCROLL, TEXT("SM_CYVSCROLL"), TEXT("Vertical scroll arrow height"),
    SM_CXHSCROLL, TEXT("SM_CXHSCROLL"), TEXT("Horizontal scroll arrow width"),
    SM_DEBUG, TEXT("SM_DEBUG"), TEXT("Debug version flag"),
    SM_SWAPBUTTON, TEXT("SM_SWAPBUTTON"), TEXT("Mouse buttons swapped flag"),
    SM_CXMIN, TEXT("SM_CXMIN"), TEXT("Minimum window width"),
    SM_CYMIN, TEXT("SM_CYMIN"), TEXT("Minimum window height"),
    SM_CXSIZE, TEXT("SM_CXSIZE"), TEXT("Min/Max/Close button width"),
    SM_CYSIZE, TEXT("SM_CYSIZE"), TEXT("Min/Max/Close button height"),
    SM_CXSIZEFRAME, TEXT("SM_CXSIZEFRAME"), TEXT("Window sizing frame width"),
    SM_CYSIZEFRAME, TEXT("SM_CYSIZEFRAME"), TEXT("Window sizing frame height"),
    SM_CXMINTRACK, TEXT("SM_CXMINTRACK"), TEXT("Minimum window tracking width"),
    SM_CYMINTRACK, TEXT("SM_CYMINTRACK"), TEXT("Minimum window tracking height"),
    SM_CXDOUBLECLK, TEXT("SM_CXDOUBLECLK"), TEXT("Double click x tolerance"),
    SM_CYDOUBLECLK, TEXT("SM_CYDOUBLECLK"), TEXT("Double click y tolerance"),
    SM_CXICONSPACING, TEXT("SM_CXICONSPACING"), TEXT("Horizontal icon spacing"),
    SM_CYICONSPACING, TEXT("SM_CYICONSPACING"), TEXT("Vertical icon spacing"),
    SM_MENUDROPALIGNMENT, TEXT("SM_MENUDROPALIGNMENT"), TEXT("Left or right menu drop"),
    SM_PENWINDOWS, TEXT("SM_PENWINDOWS"), TEXT("Pen extensions installed"),
    SM_DBCSENABLED, TEXT("SM_DBCSENABLED"), TEXT("Double-Byte Char Set enabled"),
    SM_CMOUSEBUTTONS, TEXT("SM_CMOUSEBUTTONS"), TEXT("Number of mouse buttons"),
    SM_SECURE, TEXT("SM_SECURE"), TEXT("Security present flag"),
    SM_CXEDGE, TEXT("SM_CXEDGE"), TEXT("3-D border width"),
    SM_CYEDGE, TEXT("SM_CYEDGE"), TEXT("3-D border height"),
    SM_CXMINSPACING, TEXT("SM_CXMINSPACING"), TEXT("Minimized window spacing width"),
    SM_CYMINSPACING, TEXT("SM_CYMINSPACING"), TEXT("Minimized window spacing height"),
    SM_CXSMICON, TEXT("SM_CXSMICON"), TEXT("Small icon width"),
    SM_CYSMICON, TEXT("SM_CYSMICON"), TEXT("Small icon height"),
    SM_CYSMCAPTION, TEXT("SM_CYSMCAPTION"), TEXT("Small caption height"),
    SM_CXSMSIZE, TEXT("SM_CXSMSIZE"), TEXT("Small caption button width"),
    SM_CYSMSIZE, TEXT("SM_CYSMSIZE"), TEXT("Small caption button height"),
    SM_CXMENUSIZE, TEXT("SM_CXMENUSIZE"), TEXT("Menu bar button width"),
    SM_CYMENUSIZE, TEXT("SM_CYMENUSIZE"), TEXT("Menu bar button height"),
    SM_ARRANGE, TEXT("SM_ARRANGE"), TEXT("How minimized windows arranged"),
    SM_CXMINIMIZED, TEXT("SM_CXMINIMIZED"), TEXT("Minimized window width"),
    SM_CYMINIMIZED, TEXT("SM_CYMINIMIZED"), TEXT("Minimized window height"),
    SM_CXMAXTRACK, TEXT("SM_CXMAXTRACK"), TEXT("Maximum draggable width"),
    SM_CYMAXTRACK, TEXT("SM_CYMAXTRACK"), TEXT("Maximum draggable height"),
    SM_CXMAXIMIZED, TEXT("SM_CXMAXIMIZED"), TEXT("Width of maximized window"),
    SM_CYMAXIMIZED, TEXT("SM_CYMAXIMIZED"), TEXT("Height of maximized window"),
    SM_NETWORK, TEXT("SM_NETWORK"), TEXT("Network present flag"),
    SM_CLEANBOOT, TEXT("SM_CLEANBOOT"), TEXT("How system was booted"),
    SM_CXDRAG, TEXT("SM_CXDRAG"), TEXT("Avoid drag x tolerance"),
    SM_CYDRAG, TEXT("SM CYDRAG"), TEXT("Avoid drag y tolerance"),
    SM_SHOWSOUNDS, TEXT("SM_SHOWSOUNDS"), TEXT("Present sounds visually"),
    SM_CXMENUCHECK, TEXT("SM_CXMENUCHECK"), TEXT("Menu check-mark width"),
    SM_CYMENUCHECK, TEXT("SM_CYMENUCHECK"), TEXT("Menu check-mark height"),
    SM_SLOWMACHINE, TEXT("SM_SLOWMACHINE"), TEXT("Slow processor flag"),
    SM_MIDEASTENABLED, TEXT("SM_MIDEASTENABLED"), TEXT("Hebrew and Arabic enabled flag"),
    SM_MOUSEWHEELPRESENT, TEXT("SM_MOUSEWHEELPRESENT"), TEXT("Mouse wheel present flag"),
    SM_XVIRTUALSCREEN, TEXT("SM_XVIRTUALSCREEN"), TEXT("Virtual screen x origin"),
    SM_YVIRTUALSCREEN, TEXT("SM_YVIRTUALSCREEN"), TEXT("Virtual screen y origin"),
    SM_CXVIRTUALSCREEN, TEXT("SM_CXVIRTUALSCREEN"), TEXT("Virtual screen width"),
    SM_CYVIRTUALSCREEN, TEXT("SM_CYVIRTUALSCREEN"), TEXT("Virtual screen height"),
    SM_CMONITORS, TEXT("SM_CMONITORS"), TEXT("Number of monitors"),
    SM_SAMEDISPLAYFORMAT, TEXT("SM_SAMEDISPLAYFORMAT"), TEXT("Same color format flag")
};
#endif

MSDN about UpdateWindow:

函数直接向窗口过程发送WM_PAINT消息指定窗口的,绕过应用程序队列。如果更新区域为空,不发送消息

要强制更新,您可以使用

手动设置更新区域
InvalidateRect(hwnd, NULL, TRUE)

WM_PAINT消息添加到hwnd的消息队列中。如果你想强制立即重绘,你可以调用UpdateWindow之后,但这不应该是必要的。