Click here to Skip to main content
15,885,887 members
Articles / Programming Languages / C++

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

Rate me:
Please Sign up or sign in to vote.
4.20/5 (6 votes)
29 Dec 2009CPOL3 min read 25.6K   378   10   9
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)


Written By
Engineer
China China
Secret..

Comments and Discussions

 
Questiondecrease memory use Pin
ruiwng23-Aug-12 15:17
ruiwng23-Aug-12 15:17 
CSS
You said that"The closer to the center, the more points there should be.",but your program didn't reflect that,you just create a set of points randomly,All the points were uniform distributed in a rectangle.
And I have a suggestion for you:
1.There is no need to maintain an array to save all the points.You can just generate a point and use it right now.In this way, the memory use will be decreased.just as follows:
<pre lang="c++">void Thread(LPVOID pvoid)
{
 int i;
 HWND hWnd;
 POINT *pt;
  ::srand (::GetTickCount ());
 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.
 {
   POINT pt;
   pt.x=GetSign()*rand()%m_nXStrength*i/10;
   pt.y=GetSign()*rand()%m_nYStrength*i/10;
  ::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.
}

2.You should include MFC42D.DLL in your resource.When I trid to run it,it just told me "The program can't start because MFC42D.DLL is missing from your computer.Try reinstalling the program to fix this program".
GeneralDemo Application Crashes Pin
only_jack29-Dec-09 5:09
only_jack29-Dec-09 5:09 
JokeRe: Demo Application Crashes Pin
Jim Crafton29-Dec-09 9:37
Jim Crafton29-Dec-09 9:37 
GeneralRe: Demo Application Crashes Pin
B Joel29-Dec-09 11:13
B Joel29-Dec-09 11:13 
GeneralRe: Demo Application Crashes Pin
Aric Wang29-Dec-09 11:16
Aric Wang29-Dec-09 11:16 
GeneralRe: Demo Application Crashes Pin
Aric Wang29-Dec-09 11:49
Aric Wang29-Dec-09 11:49 
GeneralRe: Demo Application Crashes Pin
Aric Wang29-Dec-09 11:43
Aric Wang29-Dec-09 11:43 
GeneralRe: Demo Application Crashes [modified] Pin
B Joel29-Dec-09 11:57
B Joel29-Dec-09 11:57 
GeneralRe: Demo Application Crashes Pin
Aric Wang29-Dec-09 12:36
Aric Wang29-Dec-09 12:36 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.