【问题标题】:c++ gdi animation not workingc ++ gdi动画不起作用
【发布时间】:2011-03-27 15:23:10
【问题描述】:

我正在尝试使用 gdi 创建球动画,但我无法让它工作。 我用这个创建了一个球

   Graphics graphics(hdc);

Pen pen(Color(255, 0, 0, 255)); graphics.DrawEllipse(&pen, sf, 0, 10, 10); 我有 while 循环,它循环并将 1 添加到 sf 值,基本上就像这个 sf++; 比我尝试重新粉刷窗户(它不起作用),所以最终会出现不止一个圆圈;/ 这是循环(循环是 int WM_PAINT)

while(sd==1)//sd equals 1
    {
        sf++;
        onPaint(hdc);
        InvalidateRect (hWnd, NULL, TRUE);// this should repaint the window but it doesn't
        UpdateWindow(hWnd);
    }

提前致谢 拉米

【问题讨论】:

    标签: c++ visual-c++ winapi gdi repaint


    【解决方案1】:

    为了实现动画,我建议你使用计时器。例如:

    int OnCreate(HWND window, WPARAM wParam, LPARAM lParam)
    {
       SetTimer(window, TIMER_ID, 1000, 0);
       return 0;
    }
    

    现在窗口将每秒(1000 毫秒)接收 WM_TIMER 消息。你应该处理它们:

    int OnTimer(HWND window, WPARAM wParam, LPARAM lParam)
    {
       if(TIMER_ID == wParam)
       {
          /*do stuff*/
          InvalidateRect(window, NULL, TRUE);//force window to repaint
       }
       return 0;
    }
    

    那么你需要处理 WM_PAINT 消息来进行绘图

    int OnPaint(HWND window, WPARAM wParam, LPARAM lParam)
    {
       PAINTSTRUCT ps;
       HDC dc = BeginPaint(&ps);
       Graphics graphics(hdc);
       graphics.Draw...
       EndPaint(&ps);
       return 0;
    }
    

    【讨论】:

    • umm.. 它画了一个圆圈,就是这样你可以在这里看到完整的代码pastesite.com/18049
    • @Ramiz 你应该在 WM_CREATE 消息上调用 OnCreate,在 WndProc 中:--edit:抱歉忽略评论,我没有注意到你调用了 OnCreate。
    • 好吧,现在它创建了一个 x=1 的圆,而不是它创建了 x=2 的圆............它永远不会删除旧的圆
    • 你应该先清除背景即:graphics.Clear(Color::White)
    • 您应该将 TRUE 作为 InvalidateRect 中的最后一个参数传递(我应该这样做,抱歉)。我会编辑答案。
    【解决方案2】:

    您确实意识到您正在循环中以 (sd == 1) 为条件递增 sf,对吗?这当然会无限循环或永远不会输入,因为 sd 的值没有以任何方式改变。你在这里使用过调试器吗?你为什么需要这样的循环呢?您不应该在循环中调用 OnPaint。

    如果您想要多个圆圈,只需在从函数返回之前将它们全部绘制出来。维护将用于在 OnPaint 处理程序中绘制圆圈的数据集合。

    【讨论】:

    • 我知道它会永远循环...这仅用于测试..我要做的就是每次while循环循环时循环一个圆圈,圆圈位置发生变化,但事实并非如此创建多个不同位置的圆圈。像这样我创建了一个圆圈,x 值为 1,while 循环循环,圆圈 x 现在是 2,但它使用 x vlaue 2 创建新圆圈
    • 我不想要多个圆,我只想要一个会改变其位置的圆,就像我用 x = 5px,y=10 创建的圆一样。比它将循环比它将 x 更改为 x=6px 旧的 cicler 应该消失并且应该创建 x=6 的新圆圈
    【解决方案3】:

    InvalidateRect 发送 WM_ERASEBKGND 消息,如果您在创建窗口时没有定义 WNDCLASS 结构的 hbrBackground(刷子重绘背景)成员,除非您自己处理 WM_ERASEBKGND 消息,否则它不会重绘背景.

    如果这不是问题,那么可能是因为您直接调用 UpdateWindow 而不是轮询和处理消息,WM_ERASEBKGND 消息永远不会得到处理。尝试在绘制新圆之前用背景颜色覆盖之前的圆。

    或者使用 WM_ERASEBKGRND 作为消息调用 SendMessage。

    【讨论】:

    • 我已经定义了这个画笔 hbrBackground = (HBRUSH)(COLOR_WINDOW+1);即使我删除更新也无济于事
    • 删除 UpdateWindow 不会做任何事情,因为您处于一个紧密的循环中,它显示的唯一原因是您正在调用 UpdateWindow,它直接调用您的消息处理程序。正如我所说,使用 WM_ERASEBKGND 作为消息调用 SendMessage(它也直接调用您的消息处理程序)。 InvalidateRect 只发布消息并期望您轮询消息队列来处理它们。
    • 好吧,我有 WM_ERASEBKGND 但是我应该在里面有什么像这种情况 WM_ERASEBKGND: //我应该在这里放什么 break;我应该在这里更改循环中的任何内容是完整代码pastesite.com/18047
    【解决方案4】:

    我在 msdn 上找到了一个示例,它显示了如何绘制东西 in pure win32.

    您不应该在 WM_PAINT 中调用 Invalidate 或 Updatewindow,因为 UpdateWindow 会发送一个新的 WM_PAINT 事件,并且在 下一个 wm_paint 事件之前会累积无效。

    您应该将您的代码分为两个功能,一个用于执行移动,另一个用于在当前位置绘制您的圆圈。

    您的 Mover 函数可以从任何地方调用(可能在计时器处理函数中?)并且应该以

    结尾
    InvalidateRect (hWnd, NULL, TRUE);
    UpdateWindow(hWnd);
    

    为了标记您的客户区进行重绘并通知您的窗口重绘自身。

    你的 Draw() 函数应该读取你的移动函数设置的位置,然后在这个位置周围画一个圆圈。

    (旁注:如果您想最大限度地减少闪烁并获得流畅的动画,请在启动并运行基本动画后查看双缓冲

    更新

    您的更新函数中缺少 UpdateWindow 命令 您的 OnPaint-Function 仅在您的应用程序收到 WM_PAINT 消息时调用,因此您需要发送这些消息。

    UpdateWindow 服务于这个目的

    VOID update(HDC hdc,HWND hWnd) 
    { 
        sf++; 
        FillRect(hdc,rect,(HBRUSH)(COLOR_WINDOW+1)); 
        InvalidateRect (hWnd, NULL, TRUE); 
        UpdateWindow(hWND);//<- This Line sends a wm_paint-message to your window in order to make it redraw itself
    } 
    //i didn't do any changes to the onPaint functon but here is the code for it 
    VOID onPaint(HDC hdc) 
    { 
        Graphics graphics(hdc); 
        Pen pen(Color(255, 0, 0, 255)); 
        graphics.DrawEllipse(&pen, sf , 0, 10, 10); 
    } 
    
    //here is the while loop 
    while(sd==1) 
    {   onPaint(hdc); 
        update(hdc,hWnd); 
    } 
    

    【讨论】:

    • 好的,我增加了一项新功能 VOID update(HDC hdc,HWND hWnd) { sf++; FillRect(hdc,rect,(HBRUSH)(COLOR_WINDOW+1)); InvalidateRect (hWnd, NULL, TRUE);我没有对 onPaint 函数做任何更改,但这里是它的代码 VOID onPaint(HDC hdc) { Graphics graphics(hdc);笔笔(颜色(255, 0, 0, 255)); graphics.DrawEllipse(&pen, sf, 0, 10, 10); } 这里是 while 循环 while(sd==1) { onPaint(hdc);更新(hdc,hWnd); } 现在我知道了,它创建了一个圆圈,这有什么想法吗?
    猜你喜欢
    • 2012-01-03
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多