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






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

引言
这段代码是一个简单的类,我们可以用它来抖动我们的Windows窗口。 许多即时通讯工具都有这类功能。 当你和你的朋友聊天时,你点击一个按钮,然后你和你的朋友的聊天对话框开始抖动。 我用多线程来实现它,所以它是一个非常有趣的例程。下载它并玩得开心。
背景
当即时通讯工具添加这个功能时,我总是想实现它。所以,机会来了,我将继续我的文章。 我会向你解释,这并不难。不要使用任何复杂的数据结构和算法。
使用该类
使用这个类就像吃鸡蛋一样简单,只需要几个步骤。 首先将三个文件(JitterWndClass.h,JitterWndClass.cpp和shake.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上查找。
我们只想在一个线程中更改其第二个和第三个参数。 我们启动一个线程来修改窗口的位置。 如何修改位置,我们需要数据。 看看这张图片

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

我们可以从图片中看到,基本上,它是随机排列的降序。 所以,使用代码片段,我们生成点并将其存储到一个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,¶m);
}
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日: 初次发表