?
Solved

Animation woes

Posted on 2000-02-01
12
Medium Priority
?
224 Views
Last Modified: 2010-04-10
#include <windows.h>

void DrawPolygonT(HWND &,
                          const int,
                          const int,
                          const int,
                          const int,
                          const int,
                          const int,
                          const int);
void DrawPolygonO(HWND &,
                          const int,
                          const int,
                          const int,
                          const int);
void DrawPolygonM(HWND &hwnd,
                          const int temp_start_x,
                          const int temp_start_y,
                          const int temp_width,
                          const int temp_height);

//void DrawM(HWND &, HDC &, PAINTSTRUCT &);
void WaitPeriod(int DelayFactor);

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
     static TCHAR szAppName[] = TEXT ("LineDemo") ;
     HWND         hwnd ;
     MSG          msg ;
     WNDCLASS     wndclass ;
     
     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
     wndclass.lpszMenuName  = NULL ;
     wndclass.lpszClassName = szAppName ;
     
     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, TEXT ("Program requires Windows NT!"),
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }
     
     hwnd = CreateWindow (szAppName, TEXT ("Program 2 by Thomas Knowlton"),
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, NULL, hInstance, NULL) ;
     
     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ;
     
     while (GetMessage (&msg, NULL, 0, 0))
     {
          TranslateMessage (&msg) ;
          DispatchMessage (&msg) ;
     }
     return msg.wParam ;
}


LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     static int  cxClient, cyClient ;
     HDC         hdc ;
       HDC             hdc2;
     PAINTSTRUCT ps ;
       RECT rect;
       int xcounter,
             ycounter;
       const int MAX_X = 100;
       const int MAX_Y = 100;
       const int T_X_POS = 50;
       const int O_X_POS = 200;
       const int M_X_POS = 330;
       const int O_START_X = 150;
       const int O_START_Y = 20;
       const int O_HEIGHT= 140;
       const int O_WIDTH = 80;
       const int T_START_X = 20;
       const int T_START_Y = 20;
       const int T_TOP_WIDTH = 100;
       const int T_SIDEBAR_HEIGHT = 40;
       const int T_DIST_IN = 30;
       const int T_VERTICAL_BAR_HEIGHT = 100;
       const int T_BOTTOM_WIDTH = 40;
       const int M_WIDTH = 40;
       const int M_HEIGHT = 140;

     
     switch (message)
     {
     case WM_SIZE:
          cxClient = LOWORD (lParam) ;
          cyClient = HIWORD (lParam) ;
          return 0 ;
         
     case WM_PAINT:
             hdc = BeginPaint (hwnd, &ps) ;
             for(ycounter = 300; ycounter >= 20; ycounter--)
                   {
                          DrawPolygonT(hwnd,
                              T_X_POS,
                              ycounter,
                              T_TOP_WIDTH,
                              T_SIDEBAR_HEIGHT,
                              T_DIST_IN,
                              T_VERTICAL_BAR_HEIGHT,
                              T_BOTTOM_WIDTH);
                        
                        
                  /* DrawPolygonO(hwnd,
                                hdc,
                                ps,
                                O_X_POS,
                                ycounter,
                                O_WIDTH,
                                O_HEIGHT);
                          DrawPolygonM(hwnd,
                                hdc,
                                ps,
                                M_X_POS,
                                ycounter,
                                M_WIDTH,
                                M_HEIGHT);*/
                         
                          WaitPeriod(1);                                                    
                    }
                 
          EndPaint (hwnd, &ps) ;
          return 0 ;
         
     case WM_DESTROY:
          PostQuitMessage (0) ;
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}



void DrawPolygonT(HWND &hwnd,
                          const int temp_start_x,
                          const int temp_start_y,
                          const int temp_t_top_width,
                          const int temp_sidebar_height,
                          const int temp_dist_in,
                          const int temp_vert_bar_height,
                          const int temp_bottom_width)
{

      HDC hdc;
      const int T_RED = 100;
      const int T_GREEN = 200;
      const int T_BLUE = 200;
      const int START_X = temp_start_x;
      const int START_Y = temp_start_y;
      const int T_TOP_WIDTH = temp_t_top_width;
      const int T_TOP_WAYPOINT = START_X + T_TOP_WIDTH;
      const int SIDEBAR_HEIGHT = temp_sidebar_height;
      const int DIST_IN = temp_dist_in;
      const int RIGHT_DIST_IN = T_TOP_WAYPOINT - DIST_IN;
      const int VERTICAL_BAR_HEIGHT = temp_vert_bar_height;
      const int BOTTOM_WIDTH = temp_bottom_width;
      const int NUM_POINTS = 9;

      POINT apt[NUM_POINTS];

      apt[0].x = START_X;
      apt[0].y = START_Y;

      apt[1].x = T_TOP_WAYPOINT;
      apt[1].y = START_Y;

      apt[2].x = T_TOP_WAYPOINT;
      apt[2].y = START_Y + SIDEBAR_HEIGHT;

      apt[3].x = RIGHT_DIST_IN;
      apt[3].y = START_Y + SIDEBAR_HEIGHT;

      apt[4].x = RIGHT_DIST_IN;
      apt[4].y = START_Y + SIDEBAR_HEIGHT + VERTICAL_BAR_HEIGHT;
      
      apt[5].x = RIGHT_DIST_IN - BOTTOM_WIDTH;
      apt[5].y = START_Y + SIDEBAR_HEIGHT + VERTICAL_BAR_HEIGHT;
      
      apt[6].x = RIGHT_DIST_IN - BOTTOM_WIDTH;
      apt[6].y = START_Y + SIDEBAR_HEIGHT;

      apt[7].x = START_X;
      apt[7].y = START_Y + SIDEBAR_HEIGHT;
      
      apt[8].x = START_X;
      apt[8].y = START_Y;

      hdc = GetDC(hwnd);
      SelectObject(hdc,CreateHatchBrush(HS_DIAGCROSS,RGB(T_RED, T_GREEN, T_BLUE)));
      Polygon(hdc, apt, NUM_POINTS);
      DeleteObject(GetStockObject(BLACK_PEN));
      ReleaseDC(hwnd, hdc);      
}


void DrawPolygonO(HWND &hwnd,
                          const int temp_start_x,
                          const int temp_start_y,
                          const int temp_width,
                          const int temp_height)
{

      HBRUSH hBrush;
      HDC hdc;
      const int RED = 200;
      const int GREEN = 100;
      const int BLUE = 100;
      const int START_X = temp_start_x;
      const int START_Y = temp_start_y;
      const int WIDTH = temp_width;
      const int HEIGHT= temp_height;
      const int TOP_WAYPOINT = START_X + WIDTH;
      const int NUM_POINTS = 5;

      POINT apt[NUM_POINTS];

      apt[0].x = START_X;
      apt[0].y = START_Y;

      apt[1].x = TOP_WAYPOINT;
      apt[1].y = START_Y;

      apt[2].x = TOP_WAYPOINT;
      apt[2].y = START_Y + HEIGHT;

      apt[3].x = START_X;
      apt[3].y = START_Y + HEIGHT;

      apt[4].x = START_X;
      apt[4].y = START_Y;
      
      
      hBrush = CreateHatchBrush(HS_HORIZONTAL,RGB(RED, GREEN, BLUE));
      SelectObject(hdc,hBrush);
      Polygon(hdc, apt, NUM_POINTS);
      DeleteObject(hBrush);
      //Create "inner O" by drawing a rectangle inside the "Outer O"
      //Use a WHITE_BRUSH to erase the hatch lines!
      SelectObject(hdc, GetStockObject(WHITE_BRUSH));
      Rectangle(hdc,
            START_X + 20,
            START_Y + 20,
            TOP_WAYPOINT - 20,
            START_Y + HEIGHT - 20);
      ReleaseDC(hwnd, hdc);
}


void DrawPolygonM(HWND &hwnd,
                          const int temp_start_x,
                          const int temp_start_y,
                          const int temp_width,
                          const int temp_height)
{

      HBRUSH hBrush;
      HDC hdc;
      const int RED                  = 200;
      const int GREEN                  = 100;
      const int BLUE                  = 200;
      const int START_X            = temp_start_x;
      const int START_Y            = temp_start_y;
      const int WIDTH                  = temp_width;
      const int HEIGHT            = temp_height;
      const int NUM_POINTS      = 13;

      POINT apt[NUM_POINTS];

      apt[0].x = START_X;
      apt[0].y = START_Y;

      apt[1].x = START_X + WIDTH;
      apt[1].y = START_Y;

      apt[2].x = START_X + (2 * WIDTH);
      apt[2].y = START_Y + HEIGHT - (2 * WIDTH);

      apt[3].x = START_X + (3 * WIDTH);
      apt[3].y = START_Y;

      apt[4].x = START_X + (4 * WIDTH);
      apt[4].y = START_Y;

      apt[5].x = START_X + (4 * WIDTH);
      apt[5].y = START_Y + HEIGHT;

      apt[6].x = START_X + (3 * WIDTH);
      apt[6].y = START_Y + HEIGHT;

      apt[7].x = START_X + (3 * WIDTH);
      apt[7].y = START_Y + (2 * WIDTH);

      apt[8].x = START_X + (2 * WIDTH);
      apt[8].y = START_Y + HEIGHT;

      apt[9].x = START_X + WIDTH;
      apt[9].y = START_Y + (2 * WIDTH);
      
      apt[10].x = START_X + WIDTH;
      apt[10].y = START_Y + HEIGHT;
      
      apt[11].x = START_X;
      apt[11].y = START_Y + HEIGHT;
      
      apt[12].x = START_X;
      apt[12].y = START_Y;
            
      hBrush = CreateHatchBrush(HS_HORIZONTAL,RGB(RED, GREEN, BLUE));
      SelectObject(hdc,hBrush);
      Polygon(hdc, apt, NUM_POINTS);
      DeleteObject(hBrush);
      ReleaseDC(hwnd, hdc);
}


void WaitPeriod(int DelayFactor)
{
      
      const int MAX_WAIT = 500;
      int counter1, counter2;
      if (DelayFactor < 1)
            DelayFactor = 1;
      for (counter1 = 0; counter1 < MAX_WAIT * DelayFactor; counter1++)
            for (counter2 = 0; counter2 < MAX_WAIT * DelayFactor; counter2++);
}
0
Comment
Question by:Tom Knowlton
  • 6
  • 5
12 Comments
 
LVL 31

Expert Comment

by:Zoppo
ID: 2481534
Hi knowlton,

You should give us a hint what your problem is when posting some hundred lines of code ...

ZOPPo
0
 
LVL 3

Expert Comment

by:GlennDean
ID: 2483412
One problem I see is in DrawPolyT you're call to DeleteObject is wrong.  You want to save the handle returned by CreateHatchBrush (as you did in your other two functions) and then call DeleteObject on it.
0
 
LVL 5

Author Comment

by:Tom Knowlton
ID: 2483584
Test
0
Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

 
LVL 5

Author Comment

by:Tom Knowlton
ID: 2483605
My connection went south before I could tell you guys why I posted the code.

I want the 3 block letters to come up from the bottom of the client area.  I am drawing the letters in a slightly new Y position each time, and then I want to ERASE the client area before I draw the letter in a new position (slightly higher than the last postion).  If you do this quickly, it gives the illusion that the letters are "moving" or "animated"

I have already written all the code necessary to DRAW and MOVE the letters, I just need some help getting the screen to refresh or erase properly between draws, taking into account the hdc and stuff.

My understanding is that hdc = GetDC(hwnd) returns the ENTRE client area, not jus the invalid rect.

My brain is turning to mush.  Somebody explain how I can do simple animation.

0
 
LVL 5

Author Comment

by:Tom Knowlton
ID: 2483620
GlennDean:

Consider the following code excerpt (from DrawPolyT above)


hdc = GetDC(hwnd);                       SelectObject(hdc,CreateHatchBrush(HS_DIAGCROSS,RGB(T_RED, T_GREEN, T_BLUE)));
                      Polygon(hdc, apt, NUM_POINTS);
DeleteObject(GetStockObject(BLACK_PEN));
                      ReleaseDC(hwnd, hdc

What is actually happening here in reality?  What do you see happening after each line executes and why is it wrong?

Help me understand the rationale behind hdc and Selecting / Deleting "objects" in Win32.

Thanks!
0
 
LVL 3

Accepted Solution

by:
GlennDean earned 100 total points
ID: 2483883
knowlton:
   Two comments:
1.  You're call to DeleteObject is trying to delete a system GDI object, not one you created - never suppose to do that.

2.  I think I may see one major problem you're having.  You're NOT trying to draw a polygon but rather a sequence of lines.  Function Polygon "connects the points" with the currently selected pen and then fills the enclosed area with the currently selected brush (obviously not what you want, which is to draw letters).
   So, to solve the problem you simply want to call Polyline.  Keep in mind that to draw, for ex. the letter Y, you'll have to make two calls to Polyline since you can't draw Y with one call.

On your question on why to Select/Delete GDI objects, it's basically because you don't want to hold on those resources any longer than you have to.  I know I shouldn't say this, but if the pen and hatch brush are the same every single time, just allocate them once.  BUT, if you're pen and hatch brush change all the time, delete them as soon as possible.  You'll be "shocked" at how few GDI objects you can create before things start going south on you.  In one test program, it got to something like only 1400 pens allocated and things went south (I thought it would go bad say in the millions).
   Glenn
0
 
LVL 3

Expert Comment

by:GlennDean
ID: 2483905
With Polyline you don't need the brush.

Don't forget that even if you allocate the pen once for drawing your letters, you should still

 -Draw, over the previously drawn letters with the currently selected pen, which I'll assume is white
 -Select your pen, saving old pen
 -Figure out where new letters should go
 -Draw letters
 -Select old pen

GetDC returns the client area only.  To get the entire window, call GetWindowDC.
  Glenn
0
 
LVL 3

Expert Comment

by:GlennDean
ID: 2484054
Just looked at me 'ol notes on GDI and it appears it doesn't do any harm to delete stock pens and brushes.  
  So, the following is O.K.:
HBRUSH hbrush = GetStockBrush(LTGRAY_BRUSH);
HBRUSH holdbrush = SelectBrush(hdc,hbrush);
"Do whatever code"
SelectBrush(hdc,holdbrush);
DeleteBrush(hbrush);

BUT, you can skip the call to DeleteBrush since it's a stock brush.

My assumption in my above comment is bad.  The default pen is black so, to erase the previous stuff, you need to the the stock pen white, select it, then erase what you drew before.  
0
 
LVL 5

Author Comment

by:Tom Knowlton
ID: 2488362
GlennDean:

I have not had a chance to try PolyLine instead of Polygon.

You have some good advice, I think.  As soon as I get a chance to try it out, I'll come back here and give you the points.

Thanks!

Tom
0
 
LVL 5

Author Comment

by:Tom Knowlton
ID: 2561084
I don't remember accepting this answer, but "okay".
0
 
LVL 3

Expert Comment

by:GlennDean
ID: 2561144
Did you get PoloyLine to work?
0
 
LVL 5

Author Comment

by:Tom Knowlton
ID: 2561165
Glenn:

I still haven't tried it.

Here's what I will do.  If it does not work I will come back and post a comment asking for more help.

Thanks for your help!

Tom
0

Featured Post

[Webinar] Kill tickets & tabs using PowerShell

Are you tired of cycling through the same browser tabs everyday to close the same repetitive tickets? In this webinar JumpCloud will show how you can leverage RESTful APIs to build your own PowerShell modules to kill tickets & tabs using the PowerShell command Invoke-RestMethod.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Often, when implementing a feature, you won't know how certain events should be handled at the point where they occur and you'd rather defer to the user of your function or class. For example, a XML parser will extract a tag from the source code, wh…
This article will show you some of the more useful Standard Template Library (STL) algorithms through the use of working examples.  You will learn about how these algorithms fit into the STL architecture, how they work with STL containers, and why t…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

588 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question