Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

The Winter is Too Cold, the Dialog Begins to Shake!

4.20/5 (6 votes)
29 Dec 2009CPOL3 min read 26.2K   378  
The article demonstrates a method to shake the window using multithreading. Just like some IM tools, you click a button, then the dialog begins to shake.
shakewnd.jpg

Introduction

The snippet is a simple class and we can use it to shake our Windows. Many IM tools have these kind of functions. When you chat with your friend, you click a button, then you and your friend's chatting dialog begins to shake. I do it using multithreading, so it's a very funny routine. Download it and have fun.

Background

When the IM tool adds the function, I always want to implement it. So, the chance is here, and I will move on with my article. I'll explain it to you, it is not very hard. Do not use any complex data structures and algorithms.

Using the Class

To use this class is as simple as eating eggs, it only needs some steps. First add the three files(JitterWndClass.h, JitterWndClass.cpp, and shake.wav) to your project. Warning! It's three, not two. For this reason, this time the class needs an external sound file "shake.wav". When an application calls its method to shake, at the same time play this sound file.

Just several steps to use the class:

C++
#include "JitterWndClass.h"
//Some other code...
JitterWndClass jit;
jit.Init(hWnd); 	//The method needs a handle of window to be passed in,
		// it means which window we want to shake?
//Okay, now let's shake the window, call its shake method.
jit.Shake();
//Yeah!! The window began to shake and play sound.

Having finished its usage, let's continue to discover its principle.

About how to move a window, we all can think of the function SetWindowPos()! The class just uses it. The function's usage is very important.

C++
BOOL SetWindowPos( const CWnd* pWndInsertAfter, 
	int x, int y, int cx, int cy, UINT nFlags );

To know more about it, find it on MSDN.

We want to alter its second and third parameters just in a single thread. We start a thread to modify the position of window. And how to modify the position, we need the data. Look at this picture:

property.jpg

The black points on the picture are the positions we need to generate. The closer to the center, the more points there should be. Where to get the data? Sometimes, when we design an algorithm, we can create a console application first, for it is easy to input and output data. It is easy to observe. Look at the following code, it is used to generate some digits:

C++
#include "stdafx.h"
#include <windows.h>
#include <stdlib.h>

int GetSign()
{
return (rand()%2)?-1:1;
}

int main(int argc, char* argv[])
{
::srand (::GetTickCount ());
int i;
for(i=50;i>=0;i--)
{
if(i%6==0) printf("\n");

printf("%d ",GetSign()*rand()%20*i/10);
}
return 0;
}

The result is as shown in the following picture:

con1.jpg

We can see from the picture that basically, it is randomly arranged in descending order. So, using the snippet, we generate the point and store it into a POINT array.

Generate the points' array:

C++
BOOL JitterWndClass::Init(HWND hWnd)
{
 ::srand (::GetTickCount ());
 if(pt)   //If the array already exists, delete it. We need a new one.
  free(pt);

 pt=(POINT *)malloc(sizeof(POINT)*40); //Alloc the memory for point.
 if(!pt) return FALSE;

 m_hWnd=hWnd; 	//Save the handle of the window, 
		//actually handle is an unsigned int data type.

//Below to generate the points' array via rand() .

 for(i=39;i>=0;i--)
 {
   pt[i].x=GetSign()*rand()%m_nXStrength*i/10;
   pt[i].y=GetSign()*rand()%m_nYStrength*i/10;
 }

 return TRUE;
}

Okay, now we have data. Hmm, in other words, we have points where the window should move to. Let us start a thread to move the window.

C++
 void JitterWndClass::Shake()
{
 PARAMS param;
 param.hWnd =m_hWnd;
 param.pt =pt;

 _beginthread (Thread,0,&param);
}
C++
unsigned long _beginthread( void( __cdecl *start_address )( void * ), 
	unsigned stack_size, void *arglist );

We pass a pointer of structure into a thread, so in the thread function we could get the handle of the window we should shake.

At last, we get to shake the window:

C++
void Thread(LPVOID pvoid)
{
 int i;
 HWND hWnd;
 POINT *pt;
 hWnd=((PARAMS *)pvoid)->hWnd ; //Get the parameters passed from out.
 pt=((PARAMS *)pvoid)->pt ;

 RECT rect;
 POINT op;
 ::GetClientRect (hWnd,&rect);
 op.x=rect.left-10 ;
 op.y=rect.top -5;
   
 ::ClientToScreen (hWnd,&op);

 ::PlaySound ("Shake.wav",NULL,SND_FILENAME |SND_ASYNC ); //Here is used to play sound.
 for(i=39;i>=0;i--) //Loop the points in the array and move window.
 {
  ::SetWindowPos (hWnd,0,op.x +pt[i].x,
  op.y+pt[i].y,0,0,SWP_NOSIZE|SWP_NOREPOSITION  );
  ::Sleep (20); //Wait when move once.
 }

 _endthread (); //To end the thread.
}

So tired! But so much pleasure! Haha..I hope it could help you, or give you more new ideas.

BUGS And Solution

Thanks "B Joel" for pointing out the bug and method to solve. Really thanks. When I debugged it before, I also encountered the problem of random crash.

Solution: Use the "GetWindowRect()" instead of the "GetClientRect()".

Points of Interest

I love computer programming more. I have forgotten to eat for the past few days.

History

  • 29th December, 2009: Initial post 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)