我一直在尝试使用 win32 api 来创建 GUI 问题是我正在尝试制作一个滚动面板,这有点奇怪。 我的意思是它有效,唯一的问题是当我快速滚动或执行某些操作时,顶部面板会出现错误。 对我来说,代码看起来非常复杂。创建一个新窗口,为其创建回调函数。等等..
#include <windows.h>
const char CLASS_NAME[] = "vvlxpClass";
const char SCROLL_PANEL_CLASS_NAME[] = "FunctionScClass";
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK ScrollPanelProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
typedef struct {
int thickness;
COLORREF color;
} XBORDER;
VOID CreatePanel(
HWND hwnd,
int x, int y,
int width, int height,
COLORREF color,
XBORDER border
) {
RECT rect = {x, y, x + width, y + height};
HDC hdc = GetDC(hwnd);
HBRUSH brush = CreateSolidBrush(color);
FillRect(hdc, &rect, brush);
DeleteObject(brush);
if (border.thickness > 0) {
HPEN hPen = CreatePen(PS_SOLID, border.thickness, border.color);
SelectObject(hdc, hPen);
SelectObject(hdc, GetStockObject(NULL_BRUSH));
Rectangle(hdc, x, y, x + width, y + height);
DeleteObject(hPen);
}
ReleaseDC(hwnd, hdc);
}
HWND CreateScrollPanel(
HWND hwndParent,
int x, int y,
int width, int height,
COLORREF color,
XBORDER border
) {
HWND hwndScrollPanel = CreateWindowEx(
0,
SCROLL_PANEL_CLASS_NAME,
NULL,
WS_CHILD | WS_VISIBLE | WS_VSCROLL,
x, y, width, height,
hwndParent,
NULL,
(HINSTANCE)GetWindowLongPtr(hwndParent, GWLP_HINSTANCE),
NULL
);
SetWindowLongPtr(hwndScrollPanel, GWLP_USERDATA, (LONG_PTR)color);
SetWindowLongPtr(hwndScrollPanel, GWLP_WNDPROC, (LONG_PTR)ScrollPanelProc);
return hwndScrollPanel;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
WNDCLASS wc = { };
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
RegisterClass(&wc);
wc.lpfnWndProc = ScrollPanelProc;
wc.lpszClassName = SCROLL_PANEL_CLASS_NAME;
RegisterClass(&wc);
HWND hwnd = CreateWindowEx(
0,
CLASS_NAME,
":)",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
if (hwnd == NULL) {
return 0;
}
ShowWindow(hwnd, nCmdShow);
MSG msg = { };
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
static RECT panelRect = {0, 0, 200, 0};
static HWND hwndScrollPanel;
switch (uMsg) {
case WM_SIZE: {
int height = HIWORD(lParam);
panelRect.bottom = height;
InvalidateRect(hwnd, NULL, TRUE);
} break;
case WM_CREATE: {
XBORDER border = {1, RGB(130, 135, 144)};
hwndScrollPanel = CreateScrollPanel(hwnd, 0, 1, 199, 200, RGB(255, 255, 255), border);
} break;
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
XBORDER border = {1, RGB(130, 135, 144)};
CreatePanel(hwnd, panelRect.left, panelRect.top, panelRect.right, panelRect.bottom, RGB(255, 255, 255), border);
SetTextColor(hdc, RGB(0, 0, 0));
SetBkMode(hdc, TRANSPARENT);
HFONT hFont = CreateFont(16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, VARIABLE_PITCH, TEXT("Segoe UI"));
SelectObject(hdc, hFont);
TextOut(hdc, 5, 5, "Functions", 9);
DeleteObject(hFont);
EndPaint(hwnd, &ps);
} break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK ScrollPanelProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
static int scrollPos = 0;
static int contentHeight = 800;
switch (uMsg) {
case WM_VSCROLL: {
SCROLLINFO si = { sizeof(si), SIF_ALL };
GetScrollInfo(hwnd, SB_VERT, &si);
int yPos = si.nPos;
switch (LOWORD(wParam)) {
case SB_LINEUP:
si.nPos -= 10;
break;
case SB_LINEDOWN:
si.nPos += 10;
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;
}
si.fMask = SIF_POS;
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
GetScrollInfo(hwnd, SB_VERT, &si);
if (si.nPos != yPos) {
scrollPos = si.nPos;
InvalidateRect(hwnd, NULL, TRUE);
}
} break;
case WM_MOUSEWHEEL: {
int zDelta = GET_WHEEL_DELTA_WPARAM(wParam);
int scrollLines = 3;
scrollPos -= (zDelta / WHEEL_DELTA) * scrollLines * 10;
SCROLLINFO si = { sizeof(si), SIF_RANGE | SIF_POS | SIF_PAGE };
GetScrollInfo(hwnd, SB_VERT, &si);
if (scrollPos < si.nMin) scrollPos = si.nMin;
if (scrollPos > si.nMax - (int)si.nPage + 1) scrollPos = si.nMax - (int)si.nPage + 1;
si.fMask = SIF_POS;
si.nPos = scrollPos;
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
} break;
case WM_ERASEBKGND: {
return 1;
}
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
COLORREF color = (COLORREF)GetWindowLongPtr(hwnd, GWLP_USERDATA);
HBRUSH brush = CreateSolidBrush(color);
RECT rect;
GetClientRect(hwnd, &rect);
FillRect(hdc, &rect, brush);
DeleteObject(brush);
SetTextColor(hdc, RGB(0, 0, 0));
SetBkMode(hdc, TRANSPARENT);
HFONT hFont = CreateFont(16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, VARIABLE_PITCH, TEXT("Segoe UI"));
SelectObject(hdc, hFont);
for (int i = 0; i < 10; i++) {
TextOut(hdc, 10, 25 + i * 20 - scrollPos, "Function", 8);
}
CreatePanel(hwnd, 0, 0, 200, 25, RGB(255, 255, 255), (XBORDER){0, 0});
TextOut(hdc, 5, 5, "Functions", 9);
DeleteObject(hFont);
EndPaint(hwnd, &ps);
} break;
case WM_SIZE: {
SCROLLINFO si = { sizeof(si), SIF_RANGE | SIF_PAGE };
si.nMin = 0;
si.nMax = contentHeight - 1;
si.nPage = HIWORD(lParam);
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
} break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
这是我当前的代码,正如我所说,它看起来太复杂了,我不太确定该怎么做。
尝试使用winapi“列表控件”https://learn.microsoft.com/en-us/windows/win32/controls/list-view-control-reference 我个人曾经尝试过制作一个自定义文本框,并且在滚动方面也遇到了同样的问题,直到我干脆放弃并使用 Windows 自己的 RichEdit 控件和它自己的滚动条来为我做一切。
导致问题的原因只是滚动时调用的 hdc 调用的 InvalidateRects 数量。 您可以使用 ScrollWindowEx,它针对滚动进行了优化,应该可以缓解问题:https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-scrollwindowex,但它是用滚动条校准它并不容易。
我还听说父窗口上的 WS_CLIPCHILDREN 有帮助,但我在你的代码上测试了它,但它没有做任何事情。