当前位置:C++技术网 > 资讯 > MFC实现模拟窗口拖动效果而实现的拖动矩形

MFC实现模拟窗口拖动效果而实现的拖动矩形

更新时间:2016-01-13 16:59:30浏览次数:1+次

在《win32模拟窗口拖动效果而实现的拖动矩形》里用win32完美的实现了两种窗口拖动效果。下面我们用MFC实现一遍。其实代码并没有做多大的改变,就是加上了MFC特有的封装特性。

void C拖动窗口Dlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		PAINTSTRUCT ps;
		pDC=BeginPaint(&ps);
		pDC->SelectObject(GetStockObject(WHITE_PEN));
		pDC->SelectObject(GetStockObject(GRAY_BRUSH));
		pDC->Rectangle(&rectOld);
		EndPaint(&ps);
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR C拖动窗口Dlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}



void C拖动窗口Dlg::OnLButtonDown(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	ptOld.x=point.x;
	ptOld.y=point.y;
	if(PtInRect(&rectOld,point))
	{
		IsMove=true;
	}
	else
	{
		IsMove=false;
	}
	CDialogEx::OnLButtonDown(nFlags, point);
}


void C拖动窗口Dlg::OnLButtonUp(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	if(IsMove)
	{
		p1DC=GetDC();
		IsMove=false;
		rectNew.left=rectOld.left+(point.x-ptOld.x);
		rectNew.top=rectOld.top+(point.y-ptOld.y);
		rectNew.right=rectNew.left+100;
		rectNew.bottom=rectNew.top+60;

		CopyRect(&rectOld,&rectNew);
		Invalidate();
		ReleaseDC(p1DC);
	}
	CDialogEx::OnLButtonUp(nFlags, point);
}


void C拖动窗口Dlg::OnRButtonDown(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	p1DC=GetDC();
	SetRect(&rectOld,10,10,110,70);///保存上次矩形的位置
	p1DC->SelectObject(GetStockObject(WHITE_PEN));
	p1DC->SelectObject(GetStockObject(GRAY_BRUSH));
	p1DC->Rectangle(&rectOld);
	ReleaseDC(p1DC);
	CDialogEx::OnRButtonDown(nFlags, point);
}


void C拖动窗口Dlg::OnMouseMove(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	if(IsMove)
	{
		////鼠标移动画边框
		rectMove.left=rectOld.left+(point.x-ptOld.x);
		rectMove.top=rectOld.top+(point.y-ptOld.y);     
		rectMove.right = rectMove.left+100; 
		rectMove.bottom = rectMove.top +60;
		
		/////擦掉上次的拖动的矩形轨迹
		p1DC=GetDC();
		p1DC->SelectObject(GetStockObject(WHITE_PEN));
		p1DC->SelectObject(GetStockObject(WHITE_BRUSH)); 
		p1DC->Rectangle(&rectLast);

		//////实时移动矩形
		/*p1DC->SelectObject(GetStockObject(NULL_PEN));       
		p1DC->SelectObject(GetStockObject(LTGRAY_BRUSH));     
		p1DC->Rectangle(&rectMove);       
		CopyRect(&rectLast,&rectMove);  */

		/////使用虚框代替矩形实时移动效果
		p1DC->SelectObject(GetStockObject(NULL_PEN));
        p1DC->SelectObject(GetStockObject(LTGRAY_BRUSH));
        p1DC->Rectangle(rectOld.left,rectOld.top,rectOld.right,rectOld.bottom);
        //画本次移动的矩形轨迹
        p1DC->SelectObject(GetStockObject(BLACK_PEN));
        p1DC->SelectObject(GetStockObject(NULL_BRUSH));
        p1DC->Rectangle(rectMove.left,rectMove.top,rectMove.right,rectMove.bottom);
        CopyRect(&rectLast,&rectMove);
		ReleaseDC(p1DC);
	}

	CDialogEx::OnMouseMove(nFlags, point);
}
原文中对代码有了详细的解释,我在这里补充说下,自己的理解,对于NULL_PEN,NULL_BRUSH不理解的,请看《NULL_BRUSH,NULL_PEN的理解》。
在WM_MOUSEMOVE消息函数中,我们注意下第一个注释部分及擦掉上次的矩形轨迹,那一块代码。当我们刚刚开始移动矩形的时候,这块代码并不会绘出矩形。这是因为rectLast矩形并没有初始化。假设,我们现在是使用虚框移动。
第一次,我们不会擦除掉上一次的矩形轨迹,因为我们才刚刚开始移动矩形,因此,刚刚开始的时候,我们绘制矩形就好了。在WM_MOUSEMOVE消息里,我们首先绘制自己的矩形块,而不是在WM_RBUTTONDOWN里面绘制的矩形。然后引入一个黑色的画笔画矩形边界,注意:画刷尽管能够填充矩形,但是并不会对矩形的边界
进行处理。既然我们需要虚框的边界,就将边界用黑色的画笔进行描述,但是对矩形的内部不进行处理。
其实,如果你细心的话,两种拖动效果其实只有一处不同,对于虚框拖动效果,我们就是在实时拖动矩形的效果上,对边框进行了处理。
处理完第一次的鼠标移动后下面"对上一次矩形的拖动进行擦出代码"就会响应。