65.9K
CodeProject 正在变化。 阅读更多。
Home

冬天太冷,对话框开始抖动!

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.20/5 (6投票s)

2009年12月29日

CPOL

3分钟阅读

viewsIcon

26437

downloadIcon

422

这篇文章演示了一种使用多线程抖动窗口的方法。 就像一些即时通讯工具一样,你点击一个按钮,然后对话框开始抖动。

shakewnd.jpg

引言

这段代码是一个简单的类,我们可以用它来抖动我们的Windows窗口。 许多即时通讯工具都有这类功能。 当你和你的朋友聊天时,你点击一个按钮,然后你和你的朋友的聊天对话框开始抖动。 我用多线程来实现它,所以它是一个非常有趣的例程。下载它并玩得开心。

背景

当即时通讯工具添加这个功能时,我总是想实现它。所以,机会来了,我将继续我的文章。 我会向你解释,这并不难。不要使用任何复杂的数据结构和算法。

使用该类

使用这个类就像吃鸡蛋一样简单,只需要几个步骤。 首先将三个文件(JitterWndClass.hJitterWndClass.cppshake.wav)添加到你的项目中。 警告! 是三个,不是两个。 因此,这次类需要一个外部声音文件“shake.wav”。 当应用程序调用其抖动方法时,同时播放此声音文件。

只需几个步骤即可使用该类

#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.

在使用完它之后,让我们继续探索它的原理。

关于如何移动一个窗口,我们都可以想到函数SetWindowPos()! 这个类就是使用它。 这个函数的使用非常重要。

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

要了解更多关于它的信息,请在MSDN上查找。

我们只想在一个线程中更改其第二个和第三个参数。 我们启动一个线程来修改窗口的位置。 如何修改位置,我们需要数据。 看看这张图片

property.jpg

图片上的黑点是我们应该生成的位置。 越靠近中心,应该有越多的点。 从哪里获取数据? 有时,当我们设计一个算法时,我们可以首先创建一个控制台应用程序,因为它易于输入和输出数据。 很容易观察。 看看下面的代码,它用于生成一些数字

#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;
}

结果如图所示

con1.jpg

我们可以从图片中看到,基本上,它是随机排列的降序。 所以,使用代码片段,我们生成点并将其存储到一个POINT数组中。

生成点的数组

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;
}

好的,现在我们有了数据。 嗯,换句话说,我们有了窗口应该移动到的点。 让我们开始一个线程来移动窗口。

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

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

我们将结构的一个指针传递给一个线程,因此在线程函数中我们可以获取我们应该抖动的窗口的句柄。

最后,我们开始抖动窗口

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.
}

好累!但是非常快乐! 哈哈..我希望它能帮助你,或者给你更多新的想法。

BUG 及解决方案

感谢“B Joel”指出了这个错误和解决的方法。 真的感谢。 我以前调试它时,也遇到了随机崩溃的问题。

解决方案:使用 "GetWindowRect()" 而不是 "GetClientRect()"。

关注点

我更热爱计算机编程。 过去几天我忘记了吃饭。

历史

  • 2009年12月29日: 初次发表
© . All rights reserved.