我不想每帧都画一个正弦波。在每一帧中,画完之后,角度会增加,我想有平滑的波浪移动效果,但是我不知道如何在每一帧中实现画。
这是我的代码:
#include <windows.h>
#include <cmath>
#include <iostream>
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
HWND hwnd;
float t = 0.0f;
HANDLE tickThreadHandle;
DWORD WINAPI tickThreadProc(HANDLE handle)
{
Sleep(50);
ShowWindow(hwnd, SW_SHOW);
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
RECT r;
GetWindowRect(hwnd, &r);
HPEN hPen = CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
HPEN hOldPen = static_cast<HPEN>(SelectObject(hdc, hPen));
int delay = 1000 / 50;
while (true)
{
for (int x = 0; x<r.right; x += 5, t += 0.3f)
{
LineTo(hdc, x, sin(t) * 50 + 200);
}
t += 0.1f;
Sleep(delay);
}
SelectObject(hdc, hOldPen);
DeleteObject(hPen);
EndPaint(hwnd, &ps);
}
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
{
LPCTSTR lpszClassName = L"WNDCLASS";
WNDCLASSEX wcex;
ZeroMemory(&wcex, sizeof(wcex));
wcex.cbSize = sizeof(wcex);
wcex.hInstance = hInstance;
wcex.lpszClassName = lpszClassName;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.style = CS_DBLCLKS;
wcex.lpfnWndProc = WndProc;
wcex.hbrBackground = CreateSolidBrush(RGB(0, 0, 150));
if (!RegisterClassEx(&wcex))
{
return -1;
}
hwnd = CreateWindowEx(
NULL,
lpszClassName,
L"WINDOW",
WS_OVERLAPPEDWINDOW,
0,
0,
400,
400,
HWND_DESKTOP,
NULL,
hInstance,
NULL
);
if (hwnd == NULL)
{
return -2;
}
//ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
//InvalidateRect(hwnd, NULL, TRUE);
MSG msg;
//SendMessage(hwnd, WM_PAINT, NULL, NULL);
while (GetMessage(&msg, hwnd, 0, 0) > 0)
{
/*RedrawWindow(hwnd, &windowRect, NULL, RDW_INTERNALPAINT);*/
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
{
tickThreadHandle = CreateThread(NULL, NULL, &tickThreadProc, NULL, NULL, NULL);
}
case WM_DESTROY:
{
PostQuitMessage(NULL);
}
//case WM_PAINT:
//{
//}
default:
{
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
return 0;
}
我尝试了很多方法,在我最后一次尝试中,我试图做另一个线程,并在那里画,但我的窗口甚至没有显示。我也试着给我的窗口发送消息,或者使用
WM_PAINT
函数,但是没有任何结果。我知道我可能会用错方法,请纠正我,并给我一个提示,我可以做什么。 最佳答案
SetTimer可用于(与正常消息循环一起)以最短16毫秒的间隔绘制窗口。Windows将在每个间隔发送WM_TIMER
消息,您可以在其中使窗口无效。
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
SetTimer(hwnd, 1, 20, NULL);
break;
case WM_TIMER:
InvalidateRect(hwnd, NULL, FALSE);
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
render(hwnd, hdc);
EndPaint(hwnd, &ps);
break;
}
...
}
可以修改render函数以使用
HDC
from paint函数。void render(HWND hwnd, HDC hdc)
{
...
HBRUSH hbrush = CreateSolidBrush(RGB(0, 0, 150));
HBRUSH oldbrush = (HBRUSH)SelectObject(hdc, hbrush);
FillRect(hdc, &cr, hbrush);
...
SelectObject(hdc, oldbrush);
DeleteObject(hbrush);
//Sleep <== remove the Sleep function
}
或者,您可以使用所谓的“游戏循环”和高分辨率计时器(如
std::chrono
)以较短的间隔使窗口失效。WM_PAINT
消息可以像以前一样处理。Direct3D或OpenGL游戏可能使用类似的消息循环并调用
render()
函数,但在这种情况下,我们可以调用InvalidateRect
来绘制窗口。#include <chrono>
...
MSG msg = { 0 };
while(TRUE)
{
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT) //<=== **** EDITED ****
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
typedef std::chrono::high_resolution_clock hiresclock;
static auto timer = hiresclock::now();
auto milisec = (hiresclock::now() - timer).count() / 1000000;
if(milisec > 20)
{
timer = hiresclock::now();
//... draw
}
}
}
关于c++ - WinApi在每帧绘图,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47144021/