GDI 中的像素动画

问题描述 投票:0回答:2

我是 GDI 的新手。我正在尝试在 GDI 中制作彩虹颜色效果的动画,到目前为止,我已经创建了一个不制作动画的静态彩虹。

我的动画方法是,我应该将数组元素移动到下一个位置,例如 [0,1,2] 变为 [2,0,1] 并调用

setpixelv() again
。但我觉得这样既费时又低效。

这是我的实际代码:

#include <windows.h>

const int WINDOW_WIDTH = 800;
const int WINDOW_HEIGHT = 600;
const int BAR_WIDTH = 600;
const int BAR_HEIGHT = 50;

int imageData[498 * 1] = {0xFB017D, 0xFB0278, 0xFB017D, 0xFC0280, 0xFB027A, 0xFB027A, 0xFB017C, 0xFA0175, 0xFC026E, 0xFC026C, 0xFC036B, 0xFC0266,
                          0xFC0263, 0xFC015E, 0xFC025B, 0xFB015A, 0xFB0351, 0xFB0351, 0xFC014E, 0xFC024C, 0xFC0249, 0xFC0146, 0xFC0242, 0xFC0241, 0xFD0237, 0xFD0237, 0xFD0237, 0xFD0235, 0xFD0132, 0xFD022D, 0xFD0329, 0xFC0226, 0xFC0228, 0xFC0323, 0xFC021D, 0xFC0319, 0xFE0219, 0xFD0116, 0xFD0213, 0xFC020E, 0xFC020C, 0xFC030B, 0xFB0206, 0xFB0304, 0xFB0303, 0xF90403, 0xF90304, 0xF90306, 0xFD0002, 0xFE0606, 0xFB0905, 0xF90C04, 0xFC1005, 0xFD1104, 0xFB1404, 0xFC1906, 0xF81A03, 0xFB2004, 0xFB2203, 0xFA2402, 0xFA2805, 0xF82A05, 0xF82D04, 0xFB3204, 0xFB3705, 0xF93A06, 0xFA3D06, 0xFC3F05, 0xFF4105, 0xFE4203, 0xFC4604, 0xFB4A06, 0xFB5106, 0xFC5207, 0xFB5406, 0xFC5707, 0xFB5904, 0xFB5B03, 0xFC5D02, 0xFC5E03, 0xFC6303, 0xFB6504, 0xFC6804, 0xFB6E04, 0xFC7205, 0xFC7605, 0xFC7905, 0xFD7A04, 0xF97B02, 0xFC7E03, 0xFB8102, 0xFB8402, 0xFC8A05, 0xFC8C04, 0xFA8F03, 0xFD9204, 0xFB9703, 0xFC9804, 0xFC9A03, 0xFC9D03, 0xFBA103, 0xFCA603, 0xFDAA06, 0xFEAD06, 0xFBAE06, 0xFDB306, 0xFDB805, 0xFCBC05, 0xFBBD06, 0xFAC005, 0xFCC304, 0xFEC502, 0xFACC05, 0xFBCD05, 0xFBD007, 0xFDD305, 0xFAD403, 0xFAD703, 0xF9DA03, 0xFBDC05, 0xFDE104, 0xFAE202, 0xF8E703, 0xFBED06, 0xFDEF06, 0xFCEE05, 0xFAF005, 0xFAF307, 0xFAF503, 0xF8F603, 0xF7F605, 0xF2F504, 0xF0F505, 0xEDF605, 0xECF703, 0xEBF904, 0xE6FC06, 0xE1F903, 0xDDF904, 0xDCFC05, 0xD7FB05, 0xD4FC06, 0xD3FB05, 0xCEF801, 0xCEF703, 0xCCF803, 0xC8FA05, 0xC2FA03, 0xBEFA04, 0xBAFA05, 0xB6FB04, 0xB3F902, 0xB4FA04, 0xB3F903, 0xB0FA03, 0xADFB05, 0xAAFC06,
                          0xA2FA05, 0x9EF904, 0x9CFB07, 0x98FA05, 0x94F802, 0x92F703, 0x8FF903, 0x8DFB06, 0x89FB06, 0x84FA04, 0x82FA03, 0x83FB06, 0x7DF905, 0x77F905, 0x77FA06, 0x77FA08, 0x73F906, 0x6EFA03, 0x6AFB02, 0x6AFA04, 0x68F802, 0x68FA04, 0x63F904, 0x5DF703, 0x58F804, 0x56FA05, 0x52FA04, 0x53F903, 0x4DF903, 0x4AFA04, 0x47F905, 0x47F905, 0x45F806, 0x3FF902, 0x3BF901, 0x3BFC05, 0x36FA02, 0x32F803, 0x2EF804, 0x2CF906, 0x27F904, 0x27F904, 0x26FA05, 0x1FFB03, 0x1CFB04, 0x18FA03, 0x14FA04, 0x10FA05, 0x0CFA04, 0x0CFA04, 0x0BFB04, 0x04F904, 0x04F904, 0x04F904, 0x04F904, 0x04F904, 0x04F904, 0x04F904, 0x04F904, 0x03FA0B, 0x03FA0B, 0x03FA0D, 0x04FA0F, 0x04FA13, 0x03FA15, 0x04FA19, 0x04FA1B, 0x02F922, 0x03FA23, 0x03FA27, 0x03F92A, 0x04F92F, 0x05FA33, 0x04FA37, 0x04F939, 0x05F93F, 0x06FA42, 0x05FA43, 0x05FA47, 0x04FB4B, 0x04FA4F, 0x04FA51, 0x05FA54, 0x04FA57, 0x04FA57, 0x04FA5B, 0x03FB5D, 0x03FA61, 0x03FA65, 0x04FA67, 0x04FA69, 0x04F96D, 0x04F96E, 0x04F970, 0x04F976, 0x04F97A, 0x05F980, 0x04F982, 0x04F984, 0x05F988, 0x07FB8A, 0x05FB8E, 0x03FA8F, 0x03FA92, 0x04FB93, 0x06FB96, 0x06FB96, 0x05FA9B, 0x05FA9F, 0x03FAA1, 0x04FAA5, 0x04F9A9, 0x04FBAC, 0x04FBAC, 0x04FBAC, 0x04FBB5, 0x04FBB7, 0x04FAB9, 0x04FABB, 0x04F8C2, 0x05F9C5, 0x03F9C6, 0x03F9C8, 0x04F9CE, 0x02F7CC, 0x05F7CF, 0x06F7D4, 0x03F6D8, 0x04F8DE, 0x05F8E4, 0x02F7E5, 0x03F8E7, 0x03F8E7, 0x03F8E9, 0x03F7ED, 0x04F7F1, 0x04F6F7, 0x04F6FA, 0x03F4FB, 0x05F1FF, 0x02EEFC, 0x05EEFD, 0x04E9FC, 0x05E8FB, 0x06E7FD,
                          0x04E1FB, 0x05E2FC, 0x06DDF9, 0x02D6FE, 0x01D5FA, 0x04D6F7, 0x04D1FE, 0x05CEF8, 0x06CBF6, 0x03C4FD, 0x05C2FC, 0x02BEFB, 0x03BCFC, 0x05BBFD, 0x04B5FB, 0x03B1FA, 0x04B0FC, 0x04AEFC, 0x02ABFC, 0x04ABFC, 0x03AAFB, 0x03A7FC, 0x04A4FC, 0x049FFC, 0x059BFC, 0x0498FC, 0x0592FE, 0x028FFB, 0x038BFB, 0x0389FC, 0x0586FD, 0x0482FB, 0x057FFC, 0x057FFE, 0x057CFE, 0x0277FB, 0x0474FC, 0x0671FD, 0x056BFC, 0x0468FC, 0x0468FE, 0x0466FF, 0x0361FE, 0x035BFB, 0x0659FD, 0x0354FB, 0x0354FD, 0x0654FE, 0x034FFA, 0x064EFA, 0x054AFD, 0x0446FC, 0x0343FC, 0x0442F9, 0x053FF8, 0x043BF7, 0x0338FA, 0x0536FF, 0x0734FF, 0x0530FB, 0x042DFB, 0x0528FC, 0x0223FA, 0x0521FE, 0x0720FF, 0x051DFD, 0x0517FD, 0x0415FB, 0x0412FB, 0x030FFB, 0x040DFC, 0x0509FE, 0x0406FB, 0x0203FB, 0x0201FC, 0x0402FD, 0x0601FD, 0x0600FE, 0x0302FD, 0x0402FD, 0x0801FC, 0x0B02FD, 0x0E02FA, 0x1502FC, 0x1A01FD, 0x1C01FC, 0x1C02FB, 0x2003FD, 0x2303FC, 0x2601FC, 0x2A01FB, 0x2B02FC, 0x2C02FC, 0x3001FD, 0x3201FB, 0x3801FC, 0x3A02FB, 0x3E03FD, 0x4202F9, 0x4601FC, 0x4A02FC, 0x4D02FD, 0x4D02FB, 0x4E02FA, 0x5202F7, 0x5501F7, 0x5B00FB, 0x5E02FB, 0x6303FB, 0x6502FB, 0x6701FA, 0x6802FB, 0x6B02FC, 0x6A01FC, 0x6C02FC, 0x7002FB, 0x7502FD, 0x7B02FD, 0x8002FC, 0x8401FC, 0x8602FD, 0x8902FE, 0x8D02FD, 0x8D02FD, 0x8F03FC, 0x9102FC, 0x9402FB, 0x9801FC, 0x9B02FB, 0x9E03FD, 0xA302FD, 0xA500FA, 0xAC03FE, 0xAC02FB, 0xAE01FB, 0xB203FC, 0xB500FB, 0xBC02FD, 0xBD00FC, 0xC001FE, 0xC403FE, 0xC502FC, 0xC602FA, 0xCA02FB, 0xCD02FA,
                          0xCD02FA, 0xD402FB, 0xD702FC, 0xD902FD, 0xDD02FC, 0xE102FB, 0xE402FC, 0xE802FB, 0xEC01FC, 0xED00FC, 0xF202F9, 0xF601FE, 0xF602F7, 0xF600FF, 0xF703F8, 0xFA02F9, 0xFD02F0, 0xFD02F0, 0xFD02F0, 0xFC01EE, 0xFC01EF, 0xFD03DF, 0xFC02E0, 0xFC02E0, 0xFC02DE, 0xFD03D9, 0xFC02D8, 0xFB03CD, 0xFD02CE, 0xFD02CD, 0xFD03C7, 0xFD01C6, 0xFC02BC, 0xFC02BE, 0xFB01BA, 0xFB02B4, 0xFD02B3, 0xFD02B3, 0xFC01B2, 0xFC02AE, 0xFC02AC, 0xFC01A8, 0xFC02A4, 0xFC02A1, 0xFC039F, 0xFC039F, 0xFB029E, 0xFC0298, 0xFB0294, 0xFC018F, 0xFC018E};

void AnimateRainbowBar(HDC hdc)
{
  for (int i = 0; i < 498; i++)
  {
    SetPixel(hdc, 100 + i, 100, imageData[i]);
  }
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch (msg)
  {
  case WM_PAINT:
  {
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hwnd, &ps);

    AnimateRainbowBar(hdc);

    EndPaint(hwnd, &ps);
    return 0;
  }
  case WM_DESTROY:
    PostQuitMessage(0);
    return 0;
  default:
    return DefWindowProc(hwnd, msg, wParam, lParam);
  }
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
  WNDCLASSEX wc = {sizeof(WNDCLASSEX)};
  wc.cbSize = sizeof(WNDCLASSEX);
  wc.lpfnWndProc = WindowProc;
  wc.hInstance = hInstance;
  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(0, 0, 0)); // Use window background color
  wc.lpszClassName = "RainbowBarWindow";
  RegisterClassEx(&wc);

  HWND hwnd = CreateWindowEx(0, "RainbowBarWindow", "Rainbow Bar", WS_OVERLAPPEDWINDOW,
                             100, 100, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, hInstance, NULL);

  ShowWindow(hwnd, nCmdShow);

  MSG msg;
  while (GetMessage(&msg, NULL, 0, 0))
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }

  return (int)msg.wParam;
}
c++ c winapi gdi
2个回答
0
投票

您可以使用计时器来完成此操作,如下所示:

  • 在致电
    SetTimer(hwnd, 1, 100, NULL);
    之前先致电
    ShowWindow
    。您的计时器将每 100 毫秒触发一次。
  • 处理循环颜色并使窗口无效的
    WM_TIMER
    消息,以便重新绘制它
  • 差不多就这些了
  case WM_DESTROY:
    PostQuitMessage(0);
    return 0;

  // Add this: (will be called automatically)
  case WM_TIMER:
    CycleColors();
    InvalidateRect(hwnd, NULL, FALSE);  // invalidate Window so it will be redrawn automaticalle
    return 0;
    break;
  // end Add

  default:
    return DefWindowProc(hwnd, msg, wParam, lParam);

然后编写一个

CycleColors()
函数来调整
imageData
。我让你写这个。

以后再担心效率问题。


0
投票

SetPixel
真的很慢,而且对于任何高性能来说都没什么用。

如果您想要直接的 GDI,您需要做的是构建自己的缓冲区并直接在内存中执行所有像素操作。这意味着您使用

CreateDIBitmap
构建
HBITMAP
对象,提供图像数据作为缓冲区(以适当的像素格式)。

然后,当您绘制时(例如处理

WM_PAINT
WM_ERASEBKGD
时),您需要创建
CreateCompatibleDC
来创建一个新的DC,将您的位图对象选择到该DC中,然后位块传输 (
BitBlt
) 将图像数据复制到窗口的客户区。

一次性完成整个图像,就好像您多次调用

SetPixel
,但更快。

例如

// Example variables that might hold your bitmap info
int nWidth;
int nHeight;
uint8_t pixelBuffer;   //<-- your image data
HBITMAP hBitmap;

// Example paint handler to blit contents of bitmap onto window
LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    if (msg == WM_PAINT)
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(GetHwnd(), &ps);

        // Draw my bitmap to buffer
        HDC hdcBitmap = CreateCompatibleDC(hdc);
        HBITMAP hBitmapOld = SelectBitmap(hdcBitmap, hBitmap);
        BitBlt(hdc, 0, 0, nWidth, nHeight, hdcBitmap, 0, 0, SRCCOPY);

        // Cleanup Bitamap DC
        SelectBitmap(hdcBitmap, hBitmapOld);
        DeleteDC(hdcBitmap);

        EndPaint(&ps);
        return 0;
    }
    return DefWindowProc(hWnd, msg, wParam, lParam);
}

如果你想制作动画,那么你需要一个计时器,它会定期触发并无效或直接绘制你的窗口。您可以在绘画之前更新动画。如果出现闪烁,则背景可能有问题。您可以处理

WM_ERASEBKGD
并忽略它。

© www.soinside.com 2019 - 2024. All rights reserved.