如何使MFC对话框上的控件可以拖动

有人问我,怎么才能使对话框上的控件可以通过鼠标来拖动. 他的方法是:
1) 从标准控件类派生新的类.
2) 处理控件的鼠标消息来实现拖动效果.

这样做当然可以实现,但似乎不太符合常规, 且需要对需要可拖动的所有控件进行子类化以便能响

应控件的鼠标消息. 在这里, 我写了一个类,专门用来处理对控件的拖动, 使用该类只需要少许修

改包含需要拖动的控件的对话框,而不需要对控件再做任何其它处理.

原理是这样的: 通过预处理发往对话框及其上控件的鼠标消息, 如果发现单击落在某个需要拖动的

控件上, 则启动拖动过程, 跟踪鼠标的运动, 并同时对控件做相应的位置调整. 当鼠标松开后,整

个拖动过程结束.

类 CMoveCtrlHandler 用来控制整个拖动的过程, 源代码如下:


// MoveCtrlHandler.h: interface for the CMoveCtrlHandler class.
//
//

#if !defined(AFX_MOVECTRLHANDLER_H__D2C119F0_5B9B_4759_A8EB_8B71F45402B6__INCLUDED_)
#define AFX_MOVECTRLHANDLER_H__D2C119F0_5B9B_4759_A8EB_8B71F45402B6__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <afxtempl.h>


typedef CArray<HWND, HWND>  WndowArray;


// for support move controls in the window
class CMoveCtrlHandler 
{
public:
 CMoveCtrlHandler();
 virtual ~CMoveCtrlHandler();
 // set the parent window contained the controls.
 void Initialize(HWND  hParent);
 // add a control to moveable controls array.
 void AddCtrl(HWND hCtrl);
 // hook the message send to the parent window or contorls.
 BOOL HookMessage(MSG* pMsg);
private:
 BOOL HookLoop(HWND hCtrl, POINT  pt);
 void DoMoveCtrl(HWND hCtrl, POINT ptOrig, POINT ptNew);
private:
 
 WndowArray   m_hWnds;  // a array  contained all the moveable controls
 HWND         m_hParent; // parent window of the contorls.
};

#endif //

!defined(AFX_MOVECTRLHANDLER_H__D2C119F0_5B9B_4759_A8EB_8B71F45402B6__INCLUDED_)

 

 

// MoveCtrlHandler.cpp: implementation of the CMoveCtrlHandler class.
//
//

#include "stdafx.h"
#include "MoveCtrlHandler.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

// find the index of the element from a array
template<class T>
int FindArray(CArray<T, T>& arr, T t)
{
 for(int i = 0; i < arr.GetSize(); i++)
 {
  if(arr.GetAt(i) == t)
   return i;
 }
 return  -1;
}

// get the mouse point form a message structure.
static POINT  MakeMessagePoint(const MSG*  pMsg)
{
 POINT  pt;
 pt.x = (long)(short)LOWORD(pMsg->lParam);
 pt.y = (long)(short)HIWORD(pMsg->lParam);
 return pt;
}
//
// Construction/Destruction
//

CMoveCtrlHandler::CMoveCtrlHandler()
{
 m_hParent = NULL;
}

CMoveCtrlHandler::~CMoveCtrlHandler()
{

}


void CMoveCtrlHandler::Initialize(HWND   hParent)
{
 ASSERT(hParent != NULL);
 m_hParent = hParent;
}

void CMoveCtrlHandler::AddCtrl(HWND  hCtrl)
{
 ASSERT(hCtrl  != NULL);
 int id = FindArray(m_hWnds, hCtrl);
 if(id >= 0)  return;

 m_hWnds.Add(hCtrl);
}

BOOL CMoveCtrlHandler::HookMessage(MSG* pMsg)
{
 // drag process started when right click a contorl that contained in array.
 if(pMsg->message != WM_RBUTTONDOWN)
  return FALSE;

 int id = FindArray(m_hWnds, pMsg->hwnd);
 if(id < 0) return FALSE;

 // capture the mouse point
 SetCapture(m_hParent);

 POINT  pt = MakeMessagePoint(pMsg);
 // mapping the point to parent window
 MapWindowPoints(m_hWnds[id], m_hParent, &pt, 1);

 // into dragging loop
 if(!HookLoop(m_hWnds[id], pt))
 {
  return FALSE;
 }

 return TRUE;
}

BOOL CMoveCtrlHandler::HookLoop(HWND hCtrl, POINT pt)
{
 POINT  point = pt;
 MSG    msg;
 POINT  ptNew;
 BOOL   bDrag = FALSE;

 while(GetMessage(&msg, NULL, 0, 0))
 {
  switch(msg.message)
  {
  case WM_RBUTTONDOWN:
   break;
  case WM_MOUSEMOVE:
   // dragging the control.
   ptNew = MakeMessagePoint(&msg);
   if(msg.hwnd != m_hParent)
    MapWindowPoints(msg.hwnd, m_hParent, &ptNew, 1);
   if(ptNew.x !=  point.x || ptNew.y != point.y)
   {
    DoMoveCtrl(hCtrl, point,  ptNew);
    point = ptNew;
    bDrag = TRUE;
   }
   break;
  case WM_RBUTTONUP:
   // leave the dragging mode.
   ReleaseCapture();
   // if the control isn't dragged. do default act and return
   return bDrag;
  default:
   // process the other message 
   TranslateMessage(&msg);
   DispatchMessage(&msg);
   break;
  }
 }
 return bDrag;
}

void CMoveCtrlHandler::DoMoveCtrl(HWND hCtrl, POINT ptOrig, POINT ptNew)
{
 RECT  rc;

 // get the rectangle of the control
 GetWindowRect(hCtrl, &rc);
 ScreenToClient(m_hParent, (LPPOINT)&rc.left);
 ScreenToClient(m_hParent, (LPPOINT)&rc.right);

 // calculate the new rectangle of the control.
 OffsetRect(&rc,  ptNew.x - ptOrig.x, ptNew.y - ptOrig.y);
 MoveWindow(hCtrl, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,

TRUE);
}


按如下步骤为你的对话框添加控件可拖动的功能:
1) 在对话框类声明一个CMoveCtrlHandler 成员对象.
class CMoveCtrlDlg : public CDialog
{
 ...
 // support to move controls in the dialog.
 CMoveCtrlHandler  m_movectrl;
 ...
};

2) 对话框初始化消息内添加初始化拖动控件代码并将需要拖动的控件添加到控制列表:
BOOL CMoveCtrlDlg::OnInitDialog()
{
 CDialog::OnInitDialog();
 ...

 // Set the parent window of moveable controls.
 m_movectrl.Initialize(*this);
 // make the contorl IDC_STATIC_1 to be moveable,
 //    make sure the static has SS_NOTIFY  style and its ID cannot be

IDC_STATIC.
 m_movectrl.AddCtrl(*GetDlgItem(IDC_STATIC_1));
 // make the OK button to be moveable
 m_movectrl.AddCtrl(*GetDlgItem(IDOK));
 
 // make the edit box to be moveable
 m_movectrl.AddCtrl(*GetDlgItem(IDC_EDIT1));

 return TRUE;  // return TRUE  unless you set the focus to a control
}

3) 添加虚函数PreTranslateMessage 的超越:
BOOL CMoveCtrlDlg::PreTranslateMessage(MSG* pMsg)
{
 // TODO: Add your specialized code here and/or call the base class
 m_movectrl.HookMessage(pMsg);
 
 return CDialog::PreTranslateMessage(pMsg);
}

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值