一、實(shí)現(xiàn)方法
解決無標(biāo)題欄窗口的拖動(dòng)問題有兩種方案,一種方案是使用常規(guī)思路來處理鼠標(biāo)拖拽事件,當(dāng)窗口獲得WM_LBUTTONDOWN(OnLButtonDown)時(shí),通過設(shè)置標(biāo)志并調(diào)用CWnd::SetCapture()函數(shù)來讓當(dāng)前窗口捕捉鼠標(biāo)消息,應(yīng)用程序進(jìn)入移動(dòng)模式,此時(shí)只要有WM_MOUSEMOVE消息過來,就可以據(jù)此移動(dòng)框架窗口,最后當(dāng)用戶釋放鼠標(biāo)按鈕,則WM_LBUTTONUP消息處理例程清除標(biāo)志并調(diào)用CWnd::ReleaseCapture()函數(shù)將鼠標(biāo)控制返還給Windows。這種方法比較繁瑣,首先要決定窗口準(zhǔn)備移到哪?然后要想好如何重繪窗口等等,而且根據(jù)屏幕顯示屬性對(duì)話框"效果"頁(yè)中"視覺效果"項(xiàng)的"拖動(dòng)時(shí)顯示窗口中內(nèi)容"復(fù)選框是不是選中,拖動(dòng)效果是不同的。那么你怎么知道設(shè)置的信息呢?方法是調(diào)用SystemParametersInfo(SPI_GETDRAGFULLWINDOWS)。Windows要程序員來事無巨細(xì)地處理這些繁瑣的事情真是太糟了。
由于Windows本身知道通過鼠標(biāo)點(diǎn)住標(biāo)題欄可以移動(dòng)窗口,那么能不能將鼠標(biāo)在窗口客戶區(qū)任何地方的點(diǎn)擊拖動(dòng)行為都模仿成好像是在標(biāo)題欄中一樣呢?答案是肯定的,這樣就產(chǎn)生了第二種拖動(dòng)窗口移動(dòng)的方法。實(shí)際上,用鼠標(biāo)點(diǎn)住對(duì)話框背景進(jìn)行拖動(dòng)操作并不難,但是你必須了解在標(biāo)題欄里拖動(dòng)窗口的原理。Windows首先確定鼠標(biāo)點(diǎn)中了哪個(gè)窗口,然后向那個(gè)窗口發(fā)送一個(gè)WM_NCHITTEST消息找出此窗口的哪個(gè)"非客戶區(qū)"(如邊界、最大化/最小化按鈕、菜單、標(biāo)題等等)擁有鼠標(biāo)光標(biāo)。接著默認(rèn)的窗口過程響應(yīng)消息并返回一個(gè)特定的代碼。如果鼠標(biāo)指針落在標(biāo)題欄中,那么這個(gè)特定代碼就是HTCAPTION,此時(shí)Windows便進(jìn)入拖拽模式,以便用戶能夠?qū)Υ翱谶M(jìn)行移動(dòng)操作。所以要想在客戶區(qū)里用鼠標(biāo)拖動(dòng)對(duì)話框,那么只要在客戶區(qū)里模仿標(biāo)題欄里的鼠標(biāo)拖動(dòng)行為即可。下面的代碼通過處理WM_NCHITTEST消息實(shí)現(xiàn)了對(duì)話框的拖動(dòng)操作:
UINT CMyDialog::OnNcHitTest(CPoint pt)
{
CRect rc;
GetClientRect(&rc);
ClientToScreen(&rc);
return rc.PtInRect(pt) ? HTCAPTION : CDialog::OnNcHitTest(pt);
}
上面這個(gè)代碼很容易理解,當(dāng)鼠標(biāo)落在客戶區(qū)內(nèi),函數(shù)返回HTCAPTION。對(duì)于一個(gè)簡(jiǎn)單的對(duì)話框來說,僅僅用這個(gè)代碼就完全可以實(shí)現(xiàn)在對(duì)話框背景內(nèi)的拖動(dòng)操作。因?yàn)閃indows使用z-order坐標(biāo)來確定鼠標(biāo)下是哪個(gè)窗口,所以對(duì)話框中其它的所有對(duì)象照常工作。如果用戶單擊某個(gè)控制,只要這個(gè)控制不是靜態(tài)位圖圖像或者文本,那么Windows都將鼠標(biāo)事件發(fā)送到該控制上,而不是對(duì)話框。由于靜態(tài)位圖圖像或者文本對(duì)于對(duì)話框是透明的,所以鼠標(biāo)在上面的拖動(dòng)同樣實(shí)現(xiàn)移動(dòng),而對(duì)于對(duì)話框中的編輯框、按鈕、組合框等其它非靜態(tài)控制則按通常的行為方式運(yùn)行。
如果應(yīng)用不是一個(gè)純粹的對(duì)話框程序,而是是包含CFormView或其它非對(duì)話框視圖,處理方法幾乎是一樣的,只需在視圖代碼中做一點(diǎn)小小的改動(dòng)即可,因?yàn)閃indows在發(fā)送WM_NCHITTEST消息時(shí),是將它發(fā)送到鼠標(biāo)光標(biāo)下的框架/視圖最頂層非透明窗口,由于視圖首先獲得WM_NCHITTEST消息。所以只要在視圖的WM_NCHITTEST消息處理例程中返回HTTRANSPARENT,讓視圖對(duì)鼠標(biāo)點(diǎn)擊"透明"即可。注意是在視圖中,而不是在框架中加入下面代碼:
UINT CMyView::OnNcHitTest(CPoint pt)
{
return HTTRANSPARENT;
}
這樣做以后,Windows將忽略視圖并繼續(xù)搜索能接收WM_NCHITTEST的窗口。如果順利的話,將找到父窗口,這時(shí)用與對(duì)話框相同的WM_NCHITTEST處理代碼即可,即在客戶區(qū)中的點(diǎn)擊返回HTCAPTION。你甚至可以通過鼠標(biāo)坐標(biāo)的象素計(jì)算,在規(guī)定的局部范圍內(nèi)實(shí)現(xiàn)視圖透明。
二、編程步驟
1、 啟動(dòng)Visual C 6.0,生成一個(gè)基于對(duì)話框的應(yīng)用程序,將該程序命名為"DragMovDlg";
2、 將程序中對(duì)話框的Style設(shè)置為"PopUp",Border設(shè)置為"None";
3、 使用Class Wizard為對(duì)話框添加WM_NCHITTEST消息響應(yīng)處理函數(shù);
4、 添加代碼,編譯運(yùn)行程序。
三、程序代碼
/////////////////////////////////////////////// DragMoveDlgDlg.h : header file
#if !defined(AFX_DRAGMOVEDLGDLG_H__4E4722C8_DE78_4AEC_97BC_73CEB2B525B3__INCLUDED_)
#define AFX_DRAGMOVEDLGDLG_H__4E4722C8_DE78_4AEC_97BC_73CEB2B525B3__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CMyDialog : public CDialog
{
// Construction
public:
CMyDialog(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CMyDialog)
enum { IDD = IDD_DRAGMOVEDLG_DIALOG };
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMyDialog)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
轉(zhuǎn)載請(qǐng)說明出處:六百號(hào)技術(shù) - SEO優(yōu)化,網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)絡(luò)編程,軟件技巧,網(wǎng)絡(luò)知識(shí),系統(tǒng)技術(shù) ? 在VC 中實(shí)現(xiàn)無標(biāo)題欄對(duì)話框的拖動(dòng)
標(biāo)簽: