利用BCB編寫具有"磁性"特徵的視窗 (轉)

worldblog發表於2007-12-15
利用BCB編寫具有"磁性"特徵的視窗 (轉)[@more@]


   利用BCB編寫具有"磁性"特徵的視窗

黑龍江省五大連池市馬明臣

一些著名的共享不但功能卓著,而且在介面的設計技巧上往往領導了一種時尚,就是其中的一個代表。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(T *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、98系統下透過。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-993837/,如需轉載,請註明出處,否則將追究法律責任。

相關文章