📄 dragdrop.cpp
字号:
////////////////////////////////////////////////////////////////// MSDN Magazine -- October 2004// If this code works, it was written by Paul DiLascia.// If not, I don't know who wrote it.// Compiles with Visual Studio .NET 2003 on Windows XP. Tab size=3.
//
// heavily modded by .dan.g.
//#include "stdafx.h"#include "DragDrop.h"
#include <windowsx.h> // for GET_X_LPARAM#include <afxpriv.h> // for AfxLoadString
#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif// Macro to get point from WM_ mouse messages#define GETPOINT(lp) (CPoint(GET_X_LPARAM(lp), GET_Y_LPARAM(lp)))CDragDropMgr::CDragDropMgr() : m_hInstOle32(NULL){ m_pMainWnd = NULL; m_hwndTracking = NULL; m_hCursorSave = NULL; m_pDragImage = NULL; m_iState = 0;
memset(&m_ddi,0,sizeof(m_ddi));}CDragDropMgr::~CDragDropMgr(){}BOOL CDragDropMgr::Install(CWnd *pMainWnd, DRAGDROPWND* ddwnds){ m_pMainWnd = pMainWnd; for (int i=0; ddwnds[i].type; i++) { HWND hwnd = ::GetDlgItem(pMainWnd->m_hWnd, ddwnds[i].id); ASSERT(hwnd && ::IsWindow(hwnd)); m_mapHwnd[hwnd] = ddwnds[i].type; } return TRUE;}
BOOL CDragDropMgr::Install(CWnd *pMainWnd, HWND hwnd, int type)
{
m_pMainWnd = pMainWnd;
m_mapHwnd[hwnd] = type;
return TRUE;
}
void CDragDropMgr::AddWindow(HWND hwnd, int type){ ASSERT(hwnd && ::IsWindow(hwnd)); m_mapHwnd[hwnd] = type;}void CDragDropMgr::RemoveWindow(HWND hwnd){ m_mapHwnd.RemoveKey(hwnd); }UINT CDragDropMgr::GetWindowType(HWND hwnd){ UINT nType = DDW_NONE; m_mapHwnd.Lookup(hwnd, nType); return nType;}//////////////////// detail: Note that this works for input only//UINT CDragDropMgr::ProcessMessage(const MSG* pMsg, BOOL bAllowNcDrag){ if (!m_pMainWnd) return FALSE; const MSG& msg = *pMsg; if (IsSourceWnd(msg.hwnd)) { if (msg.message == WM_LBUTTONDOWN || (bAllowNcDrag && msg.message == WM_NCLBUTTONDOWN) ||
msg.message == WM_RBUTTONDOWN || (bAllowNcDrag && msg.message == WM_NCRBUTTONDOWN)) return OnButtonDown(msg);
else if (msg.message == WM_MOUSEMOVE) return OnMouseMove(msg); else if (msg.message == WM_LBUTTONUP || msg.message == WM_RBUTTONUP) return OnButtonUp(msg); else if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE && m_iState) { SendDragMessage(WM_DD_DRAGABORT); SetState(NONE);
return TRUE; } } return FALSE;}//////////////////// Handle button-down message: enter CAPTURED state.//BOOL CDragDropMgr::OnButtonDown(const MSG& msg){
ASSERT (IsSourceWnd(msg.hwnd));
// convert m_ptOrg to client coords if (msg.message == WM_NCLBUTTONDOWN || msg.message == WM_NCRBUTTONDOWN)
{
// check we're not on a scrollbar
UINT nHitTest = SendMessage(msg.hwnd, WM_NCHITTEST, 0, msg.lParam);
if (nHitTest == HTHSCROLL || nHitTest == HTVSCROLL)
return FALSE;
CPoint pt = GETPOINT(msg.lParam);
::ScreenToClient(msg.hwnd, &pt);
// or above or below the client area
CRect rClient;
::GetClientRect(msg.hwnd, rClient);
if (pt.y < rClient.top || pt.y > rClient.bottom)
return FALSE;
m_ptOrg = pt;
}
else
m_ptOrg = GETPOINT(msg.lParam);
m_hwndTracking = msg.hwnd;
SetState(CAPTURED);
return FALSE;}//////////////////// Handle mousemove: enter DRAGGING state.//BOOL CDragDropMgr::OnMouseMove(const MSG& msg){ if (!IsCaptured()) return FALSE;
BOOL bLButtonDown = (GetKeyState(VK_LBUTTON) & 0x8000);
BOOL bRButtonDown = (GetKeyState(VK_RBUTTON) & 0x8000);
// check mouse button is still down
if (!bLButtonDown && !bRButtonDown)
{
SetState(NONE);
return FALSE;
} CWnd* pWnd = CWnd::FromHandle(m_hwndTracking); CPoint pt = GETPOINT(msg.lParam); if (IsDragging()) {
// already dragging: move drag image
pWnd->ClientToScreen(&pt); // convert to screen coords
// get new target window if any
m_ddi.pt = pt;
m_pMainWnd->ScreenToClient(&m_ddi.pt); // convert to main window coords
HWND hwndTarget = ::ChildWindowFromPoint(*m_pMainWnd, m_ddi.pt);
if (hwndTarget)
{
m_pMainWnd->ClientToScreen(&m_ddi.pt); // back to screen
ScreenToClient(hwndTarget, &m_ddi.pt); // then to target client coords
}
else
m_ddi.pt.x = m_ddi.pt.y = -10000;
m_ddi.hwndTarget = hwndTarget;
// m_ddi.pt is current pos in client coords of current target window
SendDragMessage(WM_DD_PREDRAGMOVE);
// now move drag image
m_pDragImage->DragMove(pt);
// update ui UINT nDropEffect = SendDragMessage(WM_DD_DRAGOVER);
// set the cursor if (!(m_ddi.hwndTarget && IsTargetWnd(m_ddi.hwndTarget)))
nDropEffect = DROPEFFECT_NONE;
HCURSOR hCur = NULL;
if (!m_hInstOle32)
m_hInstOle32 = LoadLibrary("Ole32.dll");
switch (nDropEffect)
{
case DD_DROPEFFECT_COPY:
hCur = LoadCursor(m_hInstOle32, MAKEINTRESOURCE(3));
break;
case DD_DROPEFFECT_MOVE:
hCur = LoadCursor(m_hInstOle32, MAKEINTRESOURCE(2));
break;
case DD_DROPEFFECT_LINK:
hCur = LoadCursor(m_hInstOle32, MAKEINTRESOURCE(4));
break;
case DD_DROPEFFECT_NONE:
default:
hCur = LoadCursor(m_hInstOle32, MAKEINTRESOURCE(1));
break;
}
if (hCur)
SetCursor(hCur);
} else // if (IsCaptured()) { // Not dragging yet: enter drag mode if mouse moves beyond threshhold. CPoint delta = pt - m_ptOrg; static CPoint jog(GetSystemMetrics(SM_CXDRAG), GetSystemMetrics(SM_CYDRAG)); if (abs(delta.x) > jog.x || abs(delta.y) > jog.y) { m_ddi.hwndSource = m_hwndTracking; m_ddi.pt = m_ptOrg; // start from ORIGINAL point, not where now m_ddi.hwndTarget = m_hwndTracking; m_ddi.pData = NULL;
m_ddi.bLeftDrag = bLButtonDown; // Send main window a message: enter drag mode. BOOL bDrag = SendDragMessage(WM_DD_DRAGENTER); if (bDrag && m_ddi.pData) {
SetState(bLButtonDown ? LDRAGGING : RDRAGGING); // I am now dragging
OnMouseMove(msg);
CRect rc; m_pDragImage = m_ddi.pData->CreateDragImage(pWnd, rc); m_pDragImage->BeginDrag(0, rc.BottomRight());
pWnd->ClientToScreen(&pt); m_pDragImage->DragEnter(NULL, pt); } else SetState(NONE); } } return TRUE;}
UINT CDragDropMgr::SendDragMessage(UINT nMessage)
{
if (nMessage == WM_DD_DRAGABORT)
return m_pMainWnd->SendMessage(nMessage, 0, 0);
else if (nMessage == WM_DD_DRAGOVER)
{
DragShowNolock(FALSE);
UINT nRes = m_pMainWnd->SendMessage(nMessage,
::GetDlgCtrlID(m_ddi.hwndTarget),
(LPARAM)(void*)&m_ddi);
DragShowNolock(TRUE);
return nRes;
}
// else
return m_pMainWnd->SendMessage(nMessage,
::GetDlgCtrlID(m_ddi.hwndTarget),
(LPARAM)(void*)&m_ddi);
}
void CDragDropMgr::DragShowNolock(BOOL bShow)
{
if (m_pDragImage)
m_pDragImage->DragShowNolock(bShow);
}
//////////////////// Handle button-up: drop the data and return to home state (NONE).//BOOL CDragDropMgr::OnButtonUp(const MSG& msg){
if (!IsDragging()) { SetState(NONE); return FALSE; } if (IsTargetWnd(m_ddi.hwndTarget)) { CPoint pt = GETPOINT(msg.lParam); CWnd* pWndSource = CWnd::FromHandle(m_ddi.hwndSource); CWnd* pWndTarget = CWnd::FromHandle(m_ddi.hwndTarget); pWndSource->ClientToScreen(&pt); pWndTarget->ScreenToClient(&pt); m_ddi.pt = pt; SendDragMessage(WM_DD_DRAGDROP); } else { SendDragMessage(WM_DD_DRAGABORT); } SetState(NONE); return TRUE;}//////////////////// Change state for finite-state-machine.//void CDragDropMgr::SetState(UINT iState){// TRACE(_T("CDragDropMgr::SetState %d\n"),iState); if (iState != m_iState) {
switch (iState)
{
case CAPTURED:
::SetCapture(m_hwndTracking); // capture mouse input
break;
case LDRAGGING:
case RDRAGGING: m_hCursorSave = GetCursor(); // save current cursor
break;
default: // NONE if (GetCapture() == m_hwndTracking) ::ReleaseCapture(); // release capture and.. SetCursor(m_hCursorSave); // ..restore cursor if (m_pDragImage) { m_pDragImage->DragLeave(CWnd::FromHandle(m_ddi.hwndTarget));
m_pDragImage->EndDrag(); // end drawing and..
delete m_pDragImage; // ..destroy.. m_pDragImage=NULL; // ..image list }
if (m_hwndTracking)
InvalidateRect(m_hwndTracking, NULL, FALSE);
if (m_ddi.hwndTarget)
InvalidateRect(m_ddi.hwndTarget, NULL, FALSE);
delete m_ddi.pData;
m_ddi.pData = NULL;
m_hwndTracking = NULL;
break;
}
m_iState = iState; }}//////////////////// Create the drag image: create an image list and call virtual darw function// to draw the data into the image list. Will then use this during dragging.//CImageList* CDragDropData::CreateDragImage(CWnd* pWnd, CRect& rc){
m_bitmap.DeleteObject();// const COLORREF BGCOLOR = GetSysColor(COLOR_3DLIGHT); // create memory dc compatible w/source window CWindowDC dcWin(pWnd); CDC dcMem; dcMem.CreateCompatibleDC(&dcWin); // use same font as source window CFont* pFont = pWnd->GetFont(); CFont* pOldFont = dcMem.SelectObject(pFont); // get size of drag image CSize sz = OnGetDragSize(dcMem); // call virtual fn to get size rc = CRect(CPoint(0,0), sz); // create image list: create bitmap and draw into it m_bitmap.CreateCompatibleBitmap(&dcWin, sz.cx, sz.cy); CBitmap* pOldBitmap = dcMem.SelectObject(&m_bitmap); dcMem.FillSolidRect(rc, GetSysColor(COLOR_HIGHLIGHT)); dcMem.SetBkMode(TRANSPARENT); dcMem.SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
COLORREF crMask; OnDrawData(dcMem, rc, crMask); // call virtual fn to draw dcMem.SelectObject(pOldFont); dcMem.SelectObject(pOldBitmap); // create image list and add bitmap to it CImageList *pil = new CImageList(); pil->Create(sz.cx, sz.cy, ILC_COLOR24|ILC_MASK, 0, 1); pil->Add(&m_bitmap, crMask); return pil;}//////////////////// Get draw size for text: use DrawText with DT_CALCRECT.//CSize CDragDropText::OnGetDragSize(CDC& dc){ CRect rc(0,0,0,0); dc.DrawText(m_text, &rc, DT_CALCRECT); if (rc.right>MAXWIDTH) rc.right = MAXWIDTH; return rc.Size();}//////////////////// Call MFC/Windows to draw text.//void CDragDropText::OnDrawData(CDC& dc, CRect& rc, COLORREF& crMask){
crMask = 1; dc.DrawText(m_text, &rc, DT_LEFT|DT_END_ELLIPSIS);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -