3

im trying to create ball animation using gdi but i can't get it working. i created a ball using this

   Graphics graphics(hdc);

Pen pen(Color(255, 0, 0, 255)); graphics.DrawEllipse(&pen, sf , 0, 10, 10); i have while loop that loops and adds 1 to sf value basicly like this sf++; than i try to repaint the window(it doesn't work) so ill end up with more than one circle ;/ here is the loop( the loop is 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);
    }

thanks in advance Rami

Ramilol
  • 3,394
  • 11
  • 52
  • 84

4 Answers4

5

In order to achieve animation I would suggest you use a timer. For example:

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

now window will receive WM_TIMER messages every second (1000ms). You should handle them:

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

then you need to handle WM_PAINT message to do the drawing

int OnPaint(HWND window, WPARAM wParam, LPARAM lParam)
{
   PAINTSTRUCT ps;
   HDC dc = BeginPaint(&ps);
   Graphics graphics(hdc);
   graphics.Draw...
   EndPaint(&ps);
   return 0;
}
Tassos
  • 3,158
  • 24
  • 29
  • umm.. it paint one circle and that is it you can see the full code over here http://pastesite.com/18049 – Ramilol Aug 10 '10 at 08:10
  • @Ramiz you should call OnCreate on WM_CREATE message, in WndProc:--edit: sorry ignore the comment, I didn't notice that you call the OnCreate. – Tassos Aug 10 '10 at 08:48
  • ok well now it creates a cirlce with x=1 than it creates circle with x=2 ............ it never deletes the old circle – Ramilol Aug 10 '10 at 09:30
  • you should clear the background first ie: graphics.Clear(Color::White) – Tassos Aug 10 '10 at 11:42
  • You should pass TRUE as the last parameter in InvalidateRect (I should have done it, sorry). I'll edit the answer. – Tassos Aug 10 '10 at 11:51
  • can you help me with double buffer? – Ramilol Aug 10 '10 at 17:52
  • Make a global variable Bitmap as big as your window. In OnTimer draw in that bitmap. In OnPaint call graphics.DrawImage(bitmap, client_rect); to avoid flicker you should also pass a NULL_BRUSH in wcex.hbrBackground and/or call InvalidateRect with FALSE. – Tassos Aug 11 '10 at 06:58
2

You do realize that you are incrementing sf in a loop with a conditional of (sd == 1), right? That will of course just loop infinitely or never be entered because the value of sd is not being changed in any way. Have you used the debugger at all here? Why would you need such a loop anyway? You should not be calling OnPaint in a loop.

If you want more than one circle, just draw them all before returning from the function. Maintain a collection of data that will be used to draw the circles in the OnPaint handler.

Ed S.
  • 122,712
  • 22
  • 185
  • 265
  • i know it will loop for ever... this is for testing only.. all i want to do is this make one circle everytime the while loop loops the circle location changes but it doesn't it creates more than one circle with different location. like this i create a circle and the x value is 1, while loop loops and than the circle x is now 2 but it creates new circle with x vlaue 2 – Ramilol Aug 10 '10 at 04:50
  • i don't want more than one cirlce i only want one circle that will change its place like if the cicle i created with x = 5px,y=10. than it will loop than it will change the x to x=6px the older cicler should be gone and the new circle with x=6 should be created – Ramilol Aug 10 '10 at 05:04
0

InvalidateRect sends a WM_ERASEBKGND message, and if you don't have a hbrBackground (brush to repaint the background) member of the WNDCLASS structure defined when you create the window it won't redraw the background unless you handle the WM_ERASEBKGND message yourself.

If that isn't the problem, then maybe because you are calling UpdateWindow directly instead of polling and handling messages, the WM_ERASEBKGND message never gets handled. Try overwriting the previous circle with the background colour before drawing the new one.

Or call SendMessage with WM_ERASEBKGRND as the message.

Dominique McDonnell
  • 2,510
  • 16
  • 25
  • i have defind this brush hbrBackground = (HBRUSH)(COLOR_WINDOW+1); even if i delete the update it won't help – Ramilol Aug 10 '10 at 06:25
  • Deleting the UpdateWindow won't do anything as you are in a tight loop, and the only reason that it is displaying is that you are calling UpdateWindow, which calls your message handler directly. As I said, call SendMessage (which also calls your message handler directly) with WM_ERASEBKGND as the message. InvalidateRect only posts messages and expects you to poll the message queue to handle them. – Dominique McDonnell Aug 10 '10 at 06:53
  • ok so ill have the WM_ERASEBKGND but what should i have inside it like this case WM_ERASEBKGND: //what should i put here break; and should i change anything in the loop here is the full code http://pastesite.com/18047 – Ramilol Aug 10 '10 at 07:13
0

I found an example on msdn which shows how to draw stuff in pure win32.

You should not call Invalidate or Updatewindow in WM_PAINT, as UpdateWindow sends a new WM_PAINT-event, and invalidates get accumulated until the next wm_paint event.

You should divide your Code into two functions, one to perform the movement and the other to draw your circle at the current location.

Your Mover-function can be called from anywhere (perhaps in a timer handler function?) and should end with

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

In order to mark your client area for redrawal and notify your window to redraw itself.

Your Draw()-function should read the position set with your mover function, and just a draw a circle around this location.

(Sidenote: If you want to minimize flicker and get smooth animation, have a look at double buffering once you get your basic animation up and running)

UPDATE

You were missing the UpdateWindow command in your Update-function Your OnPaint-Function is only called when a WM_PAINT-message is received by your application, so you need to send those.

UpdateWindow serves this purpose

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); 
} 
sum1stolemyname
  • 4,506
  • 3
  • 26
  • 44
  • ok i greated one new function VOID update(HDC hdc,HWND hWnd) { sf++; FillRect(hdc,rect,(HBRUSH)(COLOR_WINDOW+1)); InvalidateRect (hWnd, NULL, TRUE); } 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); } now i got this it created one circle and that is it any idea ? – Ramilol Aug 10 '10 at 06:33