利用BCB编写具有"磁性"特征的窗口
黑龙江省五大连池市马明臣
一些著名的共享软件不但功能卓著,而且在程序界面的设计技巧上往往领导了一种时尚,WinAmp就是其中的一个代表。WinAmp有两个绝活,一是可以更换窗体的外观,也就是现在俗称的给软件换“皮肤”;另一个是及时磁性窗体技巧。 那么什么是磁性窗体呢?用过Winamp的用户都知道,Winamp的播放列表或均衡器在被移动的时候,仿佛会受到一股磁力,每当靠近主窗口时就一下子被“吸附”过去,自动沿边对齐。这就是磁性窗体,那么我们如何在自己的程序中实现这种奇妙的特性呢?经过笔者摸索琢磨出了实现这种“磁化”窗口的方法。该法适用于C++ builder的各个版本。下面笔者给大家介绍一下该技术。 实现粘贴的难点在于什么时候进行这个操作,假设有两个窗体Form1和Form2,移动Form2向Form1靠近,当Form2与Form1的最近距离小于一个给定值时粘贴在一起。显然,应该在移动Form2的过程中进行判断,问题是在程序的什么位置插入判断代码呢? 合理的方法是利用系统产生的消息,我们知道窗体在移动时会产生WM_WINDOWPOSCHANGING和WM_MOVING消息,移动结束后会产生WM_WINDOWPOSCHANGED和WM_MOVE消息。我们这里使用WM_WINDOWPOSCHANGING消息来实现这一功能。 下面笔者就把实现磁性窗体的方法介绍如下: 先新建一应用程序项目,把主窗口Form1适当放小些,放一个按钮组件,修改该按钮组件的Caption属性为“创建磁性窗口”双击它并在OnClick事件中写入如下代码: void __fastcall TForm1::Button1Click(TObject *Sender) { Form2= new TForm2(Application); Form2->Show();//显示磁性窗口 } 选择“File”—>“New Form”创建一个新窗口Form2,在Form2上加入一个Edit组件Edit1和一个按钮组件Button1,修改Edit的TEXT属性为50(该值为当Form2靠近Form1时距离为50像素时进行吸附,一般设为20左右即可,这里为了效果明显所以设为50像素),修改按钮的Caption属性为“磁距”,接着在这个新窗口的unit2.h文件中的private:下面加入如下变量定义: HWND snapwin;//定义Form2吸附到哪一个窗口的句柄 RECT work_area; bool snapped;//是否吸附标志 bool winprocthing; int thresh;//距离多远开始吸附 void __fastcall SettingChanged(TMessage &msg);//改变窗口大小时产生 void __fastcall WMWindowPosChanging(TWMWindowPosChanging &msg);//移动窗口时产生 void __fastcall UpdateWorkArea();刷新窗口 接着在public: // User declarations下加入如下消息: BEGIN_MESSAGE_MAP MESSAGE_HANDLER(WM_WINDOWPOSCHANGING,TWMWindowPosChanging,WMWindowPosChanging);//定义消息当窗口移动时调用WMWindowPosChanging MESSAGE_HANDLER(WM_SETTINGCHANGE,TMessage,SettingChanged); END_MESSAGE_MAP(TForm); //当窗口改变大小时调用SettingChanged 在Form2的单元文件unit.cpp中加入如下代码: void __fastcall TForm2::SettingChanged(TMessage &msg) { UpdateWorkArea(); } //--------------------------------------------------------------------------- void __fastcall TForm2::WMWindowPosChanging(TWMWindowPosChanging &msg) { RECT sr; snapped=false;//设为不吸附 //test window snapwin = Form1->Handle;//定义Form2吸附到Form1上这里如改为别的软件的窗口句柄还可以吸附到别的软件窗口上 if (snapwin && IsWindowVisible(snapwin)) /*该段得到窗口Form1的当前位置,当Form2移动时该函数判断Form2与Form1在上下左右方向上是否距离小于50,如小于50则自动改变Form2的位置,自动吸附到Form1上*/ { if (GetWindowRect(snapwin,&sr))//得到Form1的位置 { if ( (msg.WindowPos->x <= (sr.right+thresh)) && (msg.WindowPos->x >= (sr.right-thresh)) ) { if ((msg.WindowPos->y > sr.top) && (msg.WindowPos->y < sr.bottom)) { snapped=true; msg.WindowPos->x = sr.right; } } else if ((msg.WindowPos->x + msg.WindowPos->cx) >= (sr.left-thresh) && (msg.WindowPos->x + msg.WindowPos->cx) <= (sr.left+thresh)) { if ((msg.WindowPos->y > sr.top) && (msg.WindowPos->y < sr.bottom)) { snapped=true; msg.WindowPos->x = sr.left-msg.WindowPos->cx; } } if ( (msg.WindowPos->y <= (sr.bottom+thresh)) && (msg.WindowPos->y >= (sr.bottom-thresh)) ) { if ((msg.WindowPos->x > sr.left) && (msg.WindowPos->x < sr.right)) { snapped=true; msg.WindowPos->y = sr.bottom; } } else if ((msg.WindowPos->y + msg.WindowPos->cy) <= (sr.top+thresh) && (msg.WindowPos->y + msg.WindowPos->cy) >= (sr.top-thresh)) { if ((msg.WindowPos->x > sr.left) && (msg.WindowPos->x < sr.right)) { snapped=true; msg.WindowPos->y = sr.top-msg.WindowPos->cy; } } } } //测试屏幕 sr = work_area; if (abs(msg.WindowPos->x) <= (sr.left+thresh)) { snapped=true; msg.WindowPos->x = sr.left; } else if ((msg.WindowPos->x + msg.WindowPos->cx) >= (sr.right-thresh) && (msg.WindowPos->x + msg.WindowPos->cx) <= (sr.right+thresh)) { snapped=true; msg.WindowPos->x = sr.right-msg.WindowPos->cx; } if (abs(msg.WindowPos->y) <= (sr.top+thresh)) { snapped=true; msg.WindowPos->y = sr.top; } else if ((msg.WindowPos->y+msg.WindowPos->cy) >= (sr.bottom-thresh) && (msg.WindowPos->y+msg.WindowPos->cy) <= (sr.bottom+thresh)) { snapped=true; msg.WindowPos->y = sr.bottom-msg.WindowPos->cy; } } //--------------------------------------------------------------------------- void __fastcall TForm2::UpdateWorkArea() { SystemParametersInfo(SPI_GETWORKAREA, 0, &work_area, 0); } 双击“磁距”按钮加入如下代码: void __fastcall TForm2::Button1Click(TObject *Sender) { thresh = StrToInt(Edit1->Text);//设定磁性窗口距Form1为edit1中的数值时开始吸附 } 在窗体Form2的OnCreate事件中加入如下代码: void __fastcall TForm2::FormCreate(TObject *Sender) { snapped=false;//设置为不吸附 UpdateWorkArea(); thresh = StrToInt(Edit1->Text); snapwin = Form1->Handle; }
该程序在c++ builder 5.0、windows98系统下调试通过。
|