程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> WINDOWS窗口的客戶區域拖動技術及其應用

WINDOWS窗口的客戶區域拖動技術及其應用

編輯:關於C++

WINDOWS應用程序窗口一般包括兩種:普通窗口和常居頂層的無標題條高級窗口。前者是由WINDOWS內部功能定制的,它具有WINDOWS應用程序窗口的所有普通特性:具有標題條、窗口邊框、最大化按鈕、最小化按鈕和系統默認的快捷鍵及鼠標支持功能等,利用鼠標左鍵拖動該種窗口的標題條可以在屏幕上任意移動窗口,當鼠標光標停在窗口邊框上時可以改變窗口大小;後者是一種定制的高級窗口,它不具有普通窗口的任何屬性,整個窗口的控制必須由編程者來一一確定,使用這種窗口的典型實例有WINDOWS中的IME輸入法應用程序、UCWIN4.0平台、各種浮動工具箱、OFFICE中的桌面工具欄和第三方開發的漢字輸入平台等。

WINDOWS 這種無標題條常居頂層高級窗口的一個顯著特點是,不需改變窗口大小但必須具有窗口的客戶區域拖動功能。由於普通窗口的拖動功能是由系統來完成的,編制普通的應用程序根據無須考慮客戶區域拖動問題,因此一般編程人員很難遇到這個問題,更談不上如何實現這一功能了。開發者往往希望自己開發出來的軟件具有經典軟件中的窗口客戶區域拖動功能,筆者曾經利用模仿系統鼠標點擊標題條拖動窗口和WINDOWS系統內部提供的API發送函數發送內部拖動命令來實現無標題常居頂層高級窗口的客戶拖動功能,結果都不理想。後來只好在窗口函數中通過直接處理WM_LBUTTONDOWN、WM_MOUSEMOVE和WM_LBUTTONUP消息,自行控制窗口拖動的客戶命令區、拖動開始、窗口移動、拖動虛框繪制、虛框移動和拖動結束等過程,來實現高級頂層窗口的客戶區域拖動方案。下面就自己實踐經驗詳細介紹實現該方案的具體方法和主要技巧。

一、WINDOWS檢測客戶拖動命令及鼠標光標動態提示的實現方法

WINDOWS 無標題條常居頂層高級窗口的客戶區域一般分為兩種:特定客戶命令區域和非特定客戶命令區域。特定客戶命令區域是指利用"RECT"定義的特定子矩形區域,窗口函數對發生在該區域內的鼠標命令進行檢測並處理;非特定客戶命令區域是指沒有明確定義的窗口客戶區域部分,即所有特定客戶命令區域之外的部分,窗口函數根據實際需要來確定是否對該區域內發生的鼠標命令進行處理。實現常居頂層高級窗口拖動功能的首要問題,是如何檢測和處理特定客戶命令區域和非特定客戶命令區域內的鼠標命令,以及如何利用鼠標光標來動態提示用戶此時可以進行窗口的拖動操作。

1、在特定客戶區域檢測鼠標命令的方法

當窗口中設置了實現拖動功能的圖標命令按鈕時,就必須在資源文件中定義命令按鈕的特定客戶區域,該區域一般也就是顯示命令按鈕中圖標的矩形區域,這個區域的定義方法為"RECT DragRT",其中DragRT為定義的檢測鼠標命令矩形區域,它用DragRT.LEFT、DragRT.TOP、DragRT.RIGHT和DragRT.BOTTOM四個參數來描述矩形區域相對於窗口客戶區域左上角的相對坐標值,這四個參數必須事先定義具體的數值,也可以利用"SETRECT"函數直接填充。

窗口函數在處理鼠標消息WM_LBUTTONDOWN時,在接收系統傳遞的鼠標位置參數lParam後,通過MAKEPOINT( )函數將其轉換為窗口坐標值,利用判斷某坐標點是否位於特定矩形區域內的函數PtInRect(),就可以判斷鼠標指針是否點擊在拖動命令按鈕之內,從而完成窗口拖動功能的啟動任務。其描述性功能代碼示例如下:

case WM_LBUTTONDOWN://鼠標光標點擊處理
   POINT pt;//鼠標在屏幕上位置指針,包括pt.X和pt.Y兩個參數,
   //該指針值利用MAKEPOINT通過lParam參數轉換而來
   pt=MAKEPOINT(lParam); //獲取鼠標當前屏幕位置指針
   if(PtInRect(&DragRT,pt)){//判斷鼠標是否點擊在拖動按鈕內
   //實現鼠標拖動窗口方案的啟動功能
   } else {
   //進行其它特定或非特定命令客戶區域判斷處理
   }
   break;

2、在非特定客戶區域檢測鼠標命令的方法

當窗口應用程序中采取了非特定客戶區域拖動方法時,必須在資源文件中事先確定各個特定客戶區域的矩形坐標,這時非特定客戶區域是不規則的區域,它需要根據實際的應用程序窗口及各個命令按鈕矩形區域來確定,也就是各個命令按鈕相對於窗口矩形區域的“非”子集。窗口函數在處理鼠標消息WM_LBUTTONDOWN時,首先利用函數PtInRect()判斷當前鼠標指針是否點擊在各個命令按鈕矩形區域內,如果未點擊在任何命令按鈕區域內,則可確定鼠標點擊在非特定客戶區域內,從而實現窗口拖動功能的啟動。其描述性功能代碼示例如下:

case WM_LBUTTONDOWN: //鼠標光標點擊處理
   POINT pt; //定義鼠標在屏幕上的位置指針
   pt=MAKEPOINT(lParam); //取得鼠標光標當前位置指針
   for(I=0;I
   if(PtInRect(&DragRT[I],pt)){//DragRT[I]為按鈕矩形數組
   break; //鼠標點擊在其它按鈕上中斷
   }
   }
   if(I
   //鼠標點擊在其它特定客戶區域內則處理其它按鈕功能
   }else{
   //鼠標點擊在非客戶區域內則完成窗口拖動方案的啟動
   }
   break;

3、窗口拖動功能的鼠標光標動態提示方法

在無標題條常居頂層高級窗口應用程序中,既可以采用將特定客戶區域作為拖動命令按鈕的方法,也可以采取在非特定客戶區域檢測窗口拖動命令的方法,或者兩種方法兼顧使用。在使用第一種方法時,可以在命令按鈕中用特定的圖標或文字來提示用戶該命令按鈕的功能,而後一種方法由於矩形區域無法確定不可能用圖標或文字來提示,或根本無法顯示圖標和文字(如非特定客戶區域為窗口邊界區域等),用戶根本無法知道非特定客戶區域具有拖動窗口功能,這時唯有充分利用鼠標光標的動態提示功能,就象WINDOWS 普通窗口中鼠標光標停在窗口邊框上時鼠標光標變成雙箭頭形狀來提示用戶此時可以改變窗口大小那樣,這個功能在高級窗口界面設計中非常重要。

實現鼠標光標動態提示功能前需要定制鼠標光標形狀,窗口拖動功能的動態提示光標形狀一般為四箭頭圖案,這可以利用微軟公司的SDK、FPT3.0和VC++4.1等高級開發軟件中的資源編輯器"IMAGE EDIT"等來實現。光標資源文件一般為32X32的2色或16色.CUR圖形文件,可根據實現的功能來具體確定光標圖案或直接使用WINDOWS 系統中提供的光標資源文件,當自己利用資源編輯器繪制光標圖案後,還需要利用DEBUG. EXE程序修改光標資源文件中的鼠標光標顯示偏移坐標,以便光標圖案能象WINDOWS 系統中的動態提示光標一樣,動態提示時光標圖案中心點正好處於屏幕的當前位置。這個偏移坐標值位於光示資源文件中的10和12處的雙字節位置,如動態提示光標資源文件名為MOUSEM.CUR,要使32X32(2色)的光標圖形顯示時圖案的中心點正好處於當前屏幕位置,其修改方法如下:

C>DEBUG MOUSEM.CUR

-E 10A

XXXX:10A 00.10 00.00 00.10 00.00

-W

建立起自己的鼠標光標資源文件後,首先需要在應用程序的資源文件中定義鼠標光標,資源文件中的定義方法為:

imecurm CURSOR mousem.cur

鼠標光標資源文件只有在定義之後,才能在應用程序中利用LoadCursor()函數調入內存使用,其調用方法為:

HCURSOR hCurm;//將鼠標光標資源文件數據調入內存

hCurm=LoadCursor(hInstance,"imecurm");

當需要動態改變鼠標光標形狀的客戶區域為整個窗口或某個子窗口的全部客戶區域時,在注冊客戶應用程序窗口類時定義相應的鼠標光標資源句柄,當鼠標光標移到相應窗口內時立刻變成定制的光標形狀,移出相應窗口時自動恢復原來光標形狀。實現鼠標光標這一動態提示功能的定義方法如下:

wc.hCursor=hCurm;

當鼠標光標需要在窗口的特定客戶命令按鈕區域內或非特定客戶命令區域內進行動態提示時,就不能使用上述定義方法,必須在窗口函數處理WM_MOUSEMOVE消息時進行特殊處理:首先判斷鼠標光標指針當前位置是否在拖動命令按鈕或非特定客戶區域內移動,如果鼠標指針位置滿足拖動窗口功能區域的要求,則利用API函數SETCURSOR()改變鼠標光標圖案,提示用戶此時可以進行窗口拖動操作,並將鼠標輸入控制權交給當前窗口,同時設置改變鼠標光標標志;當鼠標指針移出拖動窗口啟動命令區域時,恢復原來鼠標光標圖案同時釋放鼠標輸入焦點控制權,並清除鼠標光標動態提示標志單元。其功能性代碼描述如下:

BOOL DragFlag; //動態提示光標標志
   case WM_MOUSEMOVE: //鼠標光標移動處理
   pt=MAKEPOINT(lParam); //鼠標光標當前位置指針
   if(PtInRect(&DragRT,pt)){//鼠標指針在拖動命令區域內則
   SetCursor(hCurm); //動態改變鼠標光標形狀
   SetCapture(hWnd); //將鼠標輸入控制權交當前窗口
   iFlag=TRUE; //設置鼠標光標形狀改變標志
   } else if(iFlag==TRUE){ //鼠標指針未在拖動命令區域內
   SetCursor(LoadCursor(NULL,IDC_ARROW));//恢復原形狀
   ReleaseCapture() //釋放鼠標輸入控制權
   iFlag=FALSE; //恢復鼠標光標形狀改變標志
   }
   break;

二、WINDOWS高級窗口拖動方案中拖動框的客戶定制方法

以上介紹了窗口拖動前鼠標光標位置檢測及客戶命令區域內拖動功能的鼠標光標動態提示方法,當用戶通過鼠標光標動態提示功能取得滿足拖動窗口條件時,通過點擊鼠標左鍵來啟動拖動方案,這時最關鍵的技術問題是鼠標拖動窗口移動過程中的拖動框顯示與擦除功能實現。窗口拖動虛框就是在WINDOWS 整個屏幕區域內顯示描述被拖動窗口大小的線框,它的大小需要根據被拖動窗口的矩形區域大小和實際需要來具體確定,一般情況下為被拖動窗口的矩形區域大小。

WINDOWS 系統中的繪圖方法是通過顯示設備描述表實現的,繪圖操作需要占用一定的GDI 資源,系統為窗口、菜單、對話框、字體和各種繪圖函數分配足夠的GDI資源,WINDOWS 95中的GDI資源要比WINDOWS3.X中的GDI資源大得多。WINDOWS中有兩種使用顯示設備描述符表的方法:更新窗口顯示客戶區域和直接操作窗口顯示客戶區域。更新窗口顯示客戶區域是直接針對應用程序窗口矩形區域而言的,在窗口函數響應WM_PAINT消息時利用圖形操作命令進行窗口更新處理:

InvalidateRect(hWnd,&WinRECT,TRUE);//WinRECT為要更新區域

UpdateWindow(hWnd);

窗口初始建立時默認更新窗口的全部區域,當要更新的矩形區域為NULL時表示更新窗口所有矩形區域。函數UpdateWindow()通知系統向要更新矩形區域的窗口發送WM_PAINT消息,窗口函數接收到WM_PAINT消息後首先利用BeginPaint()函數取得設備描述符表,然後利用圖形命令直接對顯示設備進行更新操作,最後利用EndPaint()函數通知系統更新操作結束。其描述性功能代碼如下:

case WM_PAINT:
   PAINTSTRUCT ps;
   hdc=BeginPaint(hWnd,&ps);//取得設備描述符表
   SetBkMode(hdc,OPAQUE); //設備更新方式
   SetBkColor(hdc,0x00c0c0c0);
   //更新矩形區域內圖形操作
   EndPaint(hWnd,&ps); //結束更新操作
   break;

更新窗口矩形區域直接使用窗口類中定義的屏幕畫刷,即使利用SelectObject()函數選擇相應屏幕畫刷也無效,而且更新矩形區域范圍是通過InvalidateRect()函數累加的,由UpdateWindow()函數通知系統開始進行窗口更新操作,整個過程是由系統來調度的,因此使用這種方法無法實現窗口的拖動虛框繪制和實時操作。

直接操作窗口客戶區域的方法是利用GetDC( )函數直接取得顯示設備句柄,利用各種圖形操作命令直接對顯示設備進行繪圖,它使用屏幕當前設置的畫筆和畫刷來實現各種圖形繪制操作,無須系統任何消息應用程序就可以實時地對屏幕窗口進行更新和繪圖操作。其操作過程是首先取得顯示設備描述符句柄:

HDC hDC;

hDC=GetDC(hWnd);//取得hWnd窗口設備描述符表句柄

當hWnd參數為NULL時取得的是整個屏幕的設備描述符表句柄,然後利用SelectObject()函數設置當前屏幕的畫筆和畫刷,就可以利用各種畫圖函數完成屏幕的繪圖操作,最後利用ReleaseDC( )函數釋放獲取的顯示設備描述表。由於這種方法可以直接控制當前屏幕的畫筆和畫刷,並且無需系統調度就可以直接對屏幕設備進行操作,因此利用這種方法完全可以實現窗口的拖動虛框。窗口的拖動虛框是用來描述要移動窗口大小的虛線框和實線框,當矩形拖動框為虛線時,需要利用畫點或畫線函數經過一定算法來實現,這就需要設置當前的屏幕畫筆;當窗口的拖動框為實線框時,如果利用畫線函數只需設置屏幕畫筆即可,如果利用畫矩形函數Rectangle( )在設置當前屏幕畫筆的同時必須使用SelectObject(hDC,GetStockObject(NULL_BRUSH))屏蔽掉任何屏幕畫刷,否則WINDOWS程序會很快吞筮掉所有GDI資源,相當於在屏幕設備資源中增加了無數矩形區域。

對於窗口拖動框的擦除操作,只需在拖動框繪制函數中將屏幕的圖形畫筆操作方式設置為R2_XORPEN異或方式,即SetROP2(hDC2,R2_XORPEN),在拖動框繪制結束時注意恢復,然後在窗口拖動框移動到下一個位置前,在原屏幕位置重新調用繪制函數一次將原來拖動框擦除。下面給出筆者利用畫矩形、畫線和畫點函數實現的拖動框函數,用戶在使用時可選擇自己喜歡的實線或虛線拖動框函數。

函數1為利用畫矩形函數實現的拖動實框,其特點是函數的效果高,拖動框作圖速度快;函數2為利用畫線函數實現的拖動框,其特點是通過設置不同的畫線類型可以畫虛框也可以畫實框;函數3為利用畫線函數實現的拖動虛框函數,特點是拖動虛框圖案變化靈活,不足是函數效率低作圖速度慢。函數通過參數可選擇不同的拖動虛框圖案或密度。函數3參數XY為1時與WINDOWS 3.X窗口拖動缺省虛框相同為單虛線框,如果XY參數為2 則拖動虛框為矩齒形邊框。也可以根據需要選擇不同的拖動虛框圖案和相應畫筆和畫刷以達到不同的效果。

//函數1:利用畫矩形函數實現拖動實框

void DrawMoveRect(int xx1,int yy1,int xx2,int yy2,int xy)
   {
   HDC hDC;
   int oldrop2,m,k;
   hDC = GetDC(NULL); //取得全屏幕設備描述句柄
   oldrop2= GetROP2(hDC); //取得原來屏幕畫圖方式
   SetROP2(hDC,R2_XORPEN); //設置異或屏幕畫圖方式
   SelectObject(hDC,GetStockObject(NULL_BRUSH));//屏蔽畫刷
   SelectObject(hDC2,GetStockObject(WHITE_PEN));//選擇畫筆
   for (k=0;k
   xx1-=1;
   xx2+=1;
   yy1-=1;
   yy2+=1;
   Rectangle(hDC2,xx1,yy1,xx2,yy2);
   }
   SetROP2(hDC2,oldrop2); //恢復原來作圖方式
   ReleaseDC(NULL,hDC2); //釋放設備描述符表
   }
   //函數2:利用畫線函數實現拖動實框或虛框
   void DrawMoveRect(int xx1,int yy1,int xx2,int yy2,int xy)
   { HDC hDC2;
   int oldrop2,m,k;
   hDC = GetDC(NULL); //取得全屏幕設備描述句柄
   oldrop2= GetROP2(hDC); //取得原來屏幕畫圖方式
   SetROP2(hDC,R2_XORPEN); //設置異或屏幕畫圖方式
   SelectObject(hDC,GetStockObject(NULL_BRUSH));//屏蔽畫刷
   SelectObject(hDC2,GetStockObject(WHITE_PEN));//選擇畫筆
   for (k=0;k
   xx1-=1;
   xx2+=1;
   yy1-=1;
   yy2+=1;
   MoveTo(hDC2,xx1,yy1);
   LineTo(hDC2,xx2,yy1);
   MoveTo(hDC2,xx1,yy1);
   LineTo(hDC2,xx2,yy1);
   }
   SetROP2(hDC2,oldrop2); //恢復原來作圖方式
   ReleaseDC(NULL,hDC2); //釋放設備描述符表
   }
   //函數3:利用畫點函數實現不同圖案的拖動虛框
   void DrawMoveRect(int xx1,int yy1,int xx2,int yy2,int xy)
   { HDC hDC2;
   int oldrop2,I,j,x1,x2,y1,y2;
   hDC = GetDC(NULL); //取得全屏幕設備描述句柄
   oldrop2= GetROP2(hDC); //取得原來屏幕畫圖方式
   SetROP2(hDC,R2_XORPEN); //設置異或屏幕畫圖方式
   SelectObject(hDC,GetStockObject(NULL_BRUSH));//屏蔽畫刷
   SelectObject(hDC2,GetStockObject(WHITE_PEN));//選擇畫筆
   for (j=0;j
   x1=xx1-j; //帶注釋部分為另一圖案
   x2=xx2+j;
   y1=yy1-j;
   y2=yy2+j;
   for (I=x1;I
   SetPixel(hdc,I,y1,RGB(255,0,0));
   //if (I
   for (I=y1;I
   SetPixel(hdc,x2,I,RGB(255,0,0));
   //if (I
   for (I=x2;I>x1;I-=2)
   SetPixel(hdc,I,y2,RGB(255,0,0));
   //if (I>x1+2) SetPixel(hdc,I-1,y2-1,RGB(255,0,0));}
   for (I=y2;I>y1;I-=2)
   SetPixel(hdc,x1,I,RGB(255,0,0));
   //if (I>y1+2) SetPixel(hdc,x1+1,I-1,RGB(255,0,0));}
   }
   SetROP2(hDC2,oldrop2); //恢復原來作圖方式
   ReleaseDC(NULL,hDC2); //釋放設備描述符表
   }

三、WINDOWS高級窗口客戶區域拖動技術實現的“三步曲”

WINDOWS 高級窗口的客戶區域拖動命令判斷、拖動功能的鼠標光標動態提示和定制窗口拖動框函數之後,就需要實現整個拖動方案中的拖動過程啟動、窗口拖動框移動和拖動結束處理的三步曲過程。於是必須在窗口函數中直接處理WM_LBUTTONDOWN、WM_MOUSEMOVE和WM_LBUTTONUP消息,來具體處理上述三個步驟中的細節問題。

第一步,在窗口函數中對鼠標點擊消息WM_LBUTTONDOWN進行判斷處理,以處理用戶通過鼠標光標動態提示功能獲取滿足窗口拖動條件時,按下鼠標左鍵產生的啟動拖動過程消息,其功能性代碼如下:

POINT pt;
   BOOL MoveFlag=FALSE;
   case WM_LBUTTONDOWN:
   pt = MAKEPOINT(lParam); //獲取鼠標光標指針
   if(PtInRect(&DragRT,pt)){//DragRT為拖動命令區域
   DragBegin((LPRECT)&WinRT,lParam,hWnd,2);
   //啟動窗口拖動過程
   } else {進行其它處理}
   break;

上述DragBegin( )函數為筆者開發的窗口拖動啟動函數,由於一個高級窗口應用程序中往往存在很多窗口,所以將其作為一個單獨函數處理。其中WinRT 為高級窗口矩形區域,這裡作為拖動框矩形區域參數來傳遞,lParam為鼠標光標指針長整數,hWnd為當前被拖動窗口的句柄,2 為拖動框寬度。同時需要將鼠標控制權交給當前被拖動窗口、設置拖動窗口標志單元、保存當前鼠標在屏幕上的位置並顯示被拖動窗口的拖動框。拖動功能啟動函數的原形代碼如下:

void DragBegin(
   LPRECT WinRect, //拖動框的矩形區域
   LPARAM lParam, //鼠標光標當前指針
   HWND hwnd, //當前窗口句柄
   unsigned int kk) //拖動框顯示的寬度
   {
   SetCapture(hwnd); //拖動時窗口必須具有鼠標輸入權
   MoveFlag=TRUE; //設置拖動標志
   oldmx=LOWORD(lParam);//記錄當前鼠標屏幕坐標X
   oldmy=HIWORD(lParam);//記錄當前鼠標屏幕坐標Y
   DrawMoveRect(WinRect->left,WinRect->top,//顯示拖動框
   WinRect->right,WinRect->bottom,kk);
   }

第二步,需要處理鼠標拖動窗口時的拖動框移動過程,這需要在窗口函數中進行WM_MOUSEMOVE消息處理。拖動框的移動包括上次顯示拖動框的清除和本次拖動框的顯示兩步,由於拖動框繪制函數中對當前的繪制方式進行重新設置,異或方式使得只要重新在原屏幕坐標位置處調用一次該函數即可清除拖動框,因此,在鼠標拖動窗口移動過程中顯示和清除拖動框只需要調用兩次拖動框繪制函數即可。另外,拖動框在屏幕上位置的計算方法也非常簡單,就是將當前取得的屏幕位置坐標值減去保存的前次屏幕位置坐標值所得鼠標移動偏移量,再用原來窗口屏幕左上角坐標值加上這個偏移量,就可以確定被拖動窗口和拖動框新的屏幕位置坐標值。其處理過程的描述性代碼如下:

case WM_MOUSEMOVE:
   DragMove((LPRECT)&WinRT,WinWT,WinHi,lParam,2);
   //WinRT為窗口矩形區域,WinWT為窗口寬度,WinHI為窗口高度
   } else {進行其它處理}
   break;

鑒於高級窗口應用程序一般為多個子窗口,所以將拖動框移動處理過程單獨編制成函數,並且對鼠標拖動窗口過程中,窗口不能完全位於屏幕可見區域之內進行了特殊處理,開發者可根據需要自行調整其位置,以便被拖動的窗口能夠完全被顯示於屏幕可視區域內,其拖動過程函數原形代碼部分如下:

void DragMove(
   LPRECT rcwin, //拖動框矩形區域
   unsigned int wi, //被拖動窗口寬度
   unsigned int hi, //被拖動窗口高度
   LPARAM lParam, //鼠標位置指針
   unsigned int kk) //拖動框邊框寬度
   {
   DrawMoveRect(rcwin->left,rcwin->top,
   rcwin->right,rcwin->bottom,kk);//清除上次畫拖動框
   rcwin->left+=LOWORD(lParam)-sImeG.oldmx;//計算窗口
   rcwin->top+=HIWORD(lParam)-sImeG.oldmy; //新位置
   sImeG.oldmx=LOWORD(lParam); //保存當前坐標值
   sImeG.oldmy=HIWORD(lParam);
   if (rcwin->left<0) rcwin->left=0;//對窗口超越屏幕
   if (rcwin->left>sImeG.xScrWi-wi) //可視區域處理
   rcwin->left=sImeG.xScrWi-wi;
   ii=sImeG.yScrHi-hi-(sImeG.WinVer<0x35f ? 0:BOTOFF);
   if (rcwin->top<0) rcwin->top=0; //對WIN95進行底部
   if (rcwin->top>ii) rcwin->top=ii;//特殊保留處理
   rcwin->right =rcwin->left+wi-1;
   rcwin->bottom=rcwin->top+hi-1;
   DrawMoveRect(rcwin->left,rcwin->top,
   rcwin->right,rcwin->bottom,kk);//畫新位置拖動框
   }

第三步,在鼠標拖動窗口結束時需要進行窗口的實際移動處理,這就需要在處理WM_LBUTTONUP消息時利用MOVEWINDOW()命令進行實際移動處理。同樣鑒於多窗口原因仍然需要將這個處理過程單獨形成一個函數,而且在移動窗口前還需要利用繪制函數清除屏幕上所畫的拖動框,如果窗口未完全位於屏幕的可見位置,還必須進行適當調整使被拖動的窗口能夠完全位於屏幕可視區內,同時釋放鼠標控制權並清除拖動窗口標志單元。結束過程的描述性代碼部分如下:

case WM_LBUTTONUP:
   if (sImeG.MoveFlag==TRUE){//拖動標志有效
   DragEnd((LPRECT)&WinRT,WinWT,WinHI,hWnd);
   }
   拖動結束處理函數的原形代碼部分如下:
   void DragEnd(
   LPRECT rcwin, //拖動框矩形區域
   unsigned int wi, //被拖動窗口寬度
   unsigned int hi, //被拖動窗口高度
   unsigned int kk) //拖動框邊框寬度
   {
   DrawMoveRect(rcwin->left,rcwin->top,
   rcwin->right,rcwin->bottom,1); //清除拖動框
   if (rcwin->left<0) rcwin->left=0;//對窗口超越屏幕
   if (rcwin->left>sImeG.xScrWi-wi) //可視區域處理
   rcwin->left=sImeG.xScrWi-wi;
   ii=sImeG.yScrHi-hi-(sImeG.WinVer<0x35f ? 0:BOTOFF);
   if (rcwin->top<0) rcwin->top=0; //對WIN95進行底部
   if (rcwin->top>ii) rcwin->top=ii;//特殊保留處理
   rcwin->right =rcwin->left+wi-1;
   rcwin->bottom=rcwin->top+hi-1;
   MoveWindow(hwnd,rcwin->left,rcwin->top,
   wi,hi,TRUE); //將窗口實際移到新位置
   sImeG.MoveFlag=FALSE; //清除拖動標志單元
   ReleaseCapture(); //釋放鼠標控制權
   }

四、WINDOWS高級窗口的客戶區域拖動技術的實際應用

上述介紹的WINDOWS 高級窗口客戶區域拖動技術的有關技術和拖動方案“三步曲”的實現過程,這些技術原理在WINDOWS95和WINDOWS3.X下同樣適應,但由於消息是WINDOWS系統中的最後一道防線,如果處理得不好就會使應用程序“誤入歧途”,影響開發效率和程序效果,若處理得恰到好處就會使你的應用程序具有很高的專業水准,如虎添翼。因此,實現適合自己應用程序的有效拖動方案,對開發不同應用的影響和程序的運行效率具有深遠的影響。雖然實現WINDOWS 高級窗口應用程序拖動方案的方法不止一種,但筆者仍未見過更加簡捷高效的拖動方案,本文介紹的實現方案較具有很好的適應性和優秀的運行效果,具體表現在:

開發者可根據自己的實際需要控制窗口拖動框的大小、拖動框顏色和拖動框的具體圖案,具有拖動命令區域的鼠標光標動態提示功能,窗口拖動功能的啟動、拖動過程和拖動結束處理均是獨立的子程序可提供給多窗口應用程序直接調用,啟動過程選擇靈活,在拖動結束時可隨時控制被拖動窗口全部顯示在屏幕可見區域內,其它功能擴充簡便靈活,程序的運行效果理想等等。

本文給出的WINDOWS 高級窗口拖動方案描述性功能代碼和通用子程序,均在筆者開發的“輕松使用漢字輸入法”程序中實際應用,是這個程序中實現窗口拖動功能的關鍵代碼,均在WINDOWS95和WINDOWS3.X下試用效果很好,因此推薦讀者開發應用時將其作為首選方案。

在本文介紹的基礎上,相信讀者對WINDOWS 高級窗口的客戶區域拖動技術有了全面了解,同時為開發具有客戶區域拖動窗口的應用程序提供了可行的實現方案,希望讀者在此基礎上進行深入研究,以開發出更加理想的WINDOWS 高級窗口客戶區域拖動方案,編制出更加具有專業特色的WINDOWS高級應用程序。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved