马明臣
一些著名的共享软件不但功能卓著,而且在程序界面的设计技巧上往往领导了一种时尚,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系统下调试通过。
直接添加一个MID父窗体或在已有窗体的属性中找到IsMDIContainer属性,然后设置为True,然后创建第二个窗体 ,需要加载子窗体的时候:
Dim NewMDIChild As New Form2
NewMDIChild.MdiParent = Me
NewMDIChild.Show()
Public Shared Sub CheckMDIChildForm(ByVal MDIForm As Windows.Forms.Form, ByVal MDIChildForm As Windows.Forms.Form, ByVal MDIChildFormName As String)If MDIForm.MdiChildren.Length < 1 Then
'如果没有任何一个MDI子窗体,则创该MDI子窗体的窗体实例
Dim MDIChildFrm As Windows.Forms.Form = MDIChildForm ' 定义MDI子窗体
MDIChildFrm.MdiParent = MDIForm '指定父窗体
MDIChildFrm.Show() '打开窗体
Exit Sub
Else
Dim x As Integer
Dim frmyn As Boolean
For x = 0 To (MDIForm.MdiChildren.Length) - 1
Dim tempChild As Windows.Forms.Form = CType(MDIForm.MdiChildren(x), Windows.Forms.Form)
If tempChild.Name = MDIChildFormName Then
'检测到有该MDI子窗体,设为激活 并退出循环
frmyn = True
tempChild.BringToFront()
Exit For
Else
frmyn = False
End If
Next
If Not frmyn Then
'在打开的窗体中没检测到则新建
Dim MDIChildFrm As Windows.Forms.Form = MDIChildForm ' 定义MDI子窗体
MDIChildFrm.MdiParent = MDIForm '指定父窗体
MDIChildFrm.Show() '打开窗体
End If
End If
End Sub
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)