=WM_VSCROLL(消息反射) 和 WM_VSCROLL(消息响应)的区别

=WM_VSCROLL(消息反射) 和 WM_VSCROLL(消息响应)的区别


所谓消息反射就是控件拥有者自己不处这个理消息,而是反射给控件对象本身来处理这个消息


1、“=WM_VSCROLL”是消息反射标志  , WM_VSCROLL是 消息响应的标志,在VC6.0的ClassWizard中注意会发现这两个不同的消息,VS2010中没有“=WM_VSCROLL”,但是可以通过手动添加:

消息映射宏声明:    

BEGIN_MESSAGE_MAP(CMyScrollBar, CScrollBar)
	//{{AFX_MSG_MAP(CMyScrollBar)
	ON_WM_VSCROLL()           //普通消息
	ON_WM_VSCROLL_REFLECT()  //反射消息,由控件自身处理
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()
消息响应函数

//响应“WM_VSCROLL”消息
void CMyScrollBar::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
   // TODO: Add your message handler code here and/or call default  

   CScrollBar::OnVScroll(nSBCode, nPos, pScrollBar);
}

//响应“=WM_VSCROLL”消息
void CMyScrollBar::VScroll(UINT nSBCode, UINT nPos) 
{
    // TODO: Add your message handler code here
}
          注意:上面两个“TODO”的内容是有区别的

2、以MFC基于对话框工程来讲解:

       a.  CMyDialog,CMyApp,然后添加一个CMyScrollBar:public CScrollBar类

       b.   在MyDialog.h中添加垂直滚动条,绑定一个变量

                CMyScrollBar   m_Vsrcrollbar;

      c.   在CMyDialog中OnInitDialog函数中初始化上面的变量

            

	//初始化垂直滚动条
	int i_scroMax = 100;
	m_Vscrollbar.SetScrollRange(0,i_scroMax);
	m_Vscrollbar.SetScrollPos(50);


       d.   为CMyScrollBar类添加"WM_VSCROLL"消息(这个消息是反射消息)响应函数 (通过ClassWiard)

            

      

#define INT_SBLINEUP 4
#define INT_SBLINEDOWN 4
#define INT_SBPAGEUP 25
#define INT_SBPAGEDOWN 25      //下面所有代码都会使用

void CMyScrollBar::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	// TODO: Add your message handler code here and/or call default
	int pos,*Minpos,*Maxpos;
	pos = GetScrollPos();
	GetScrollRange(Minpos,Maxpos);
	switch( nSBCode )
	{
	case SB_LINEUP:
		if( pos > *Minpos )
			pos -= INT_SBLINEUP;
		break;

	case SB_LINEDOWN:
		if( pos < *Maxpos )
			pos += INT_SBLINEDOWN;
		break;

	case SB_PAGEUP:
		if( pos-INT_SBPAGEUP > *Minpos )
			pos -= INT_SBPAGEUP;
		else
			pos = *Minpos;
		break;

	case SB_PAGEDOWN:
		if( pos+INT_SBPAGEDOWN < *Maxpos )
			pos += INT_SBPAGEDOWN;
		else
			pos = *Maxpos;
		break;

	case SB_THUMBPOSITION:
		pos = nPos;
		break;

	}
	SetScrollPos(pos,TRUE);
	CScrollBar::OnVScroll(nSBCode, nPos, pScrollBar);
}

          编译运行后,单击滚动条发现没有任何反应;在上面的函数上加断点,调试发现触发WM_VSCROLL消息后,根本没有调用这个函数。那么如何让CMyScrollBar类控件对象自己处理“WM_VSCROLL”消息呢?请看“第e步”。


      e.为CMyScrollBar类添加"=WM_VSCROLL"消息(这个消息是反射消息)响应函数 (通过类视图,右键单击类名|Add Windows Message Handler....,用ClassWizard也行)

            

           

void CMyScrollBar::VScroll(UINT nSBCode, UINT nPos) 
{
	// TODO: Add your message handler code here
	int pos,Minpos=0,Maxpos=100;
	pos = GetScrollPos();
	GetScrollRange(&Minpos,&Maxpos);
	switch( nSBCode )
	{
	case SB_LINEUP:
		if( pos > Minpos )
			pos -= INT_SBLINEUP;
		break;
		
	case SB_LINEDOWN:
		if( pos < Maxpos )
			pos += INT_SBLINEDOWN;
		break;
		
	case SB_PAGEUP:
		if( pos-INT_SBPAGEUP > Minpos )
			pos -= INT_SBPAGEUP;
		else
			pos = Minpos;
		break;
		
	case SB_PAGEDOWN:
		if( pos+INT_SBPAGEDOWN < Maxpos )
			pos += INT_SBPAGEDOWN;
		else
			pos = Maxpos;
		break;
		
	case SB_THUMBPOSITION:
		pos = nPos;
		break;
		
	}
	SetScrollPos(pos,TRUE);
}
           运行后发现垂直滚动条可以很好的运行;调试发现,触发WM_VSCROLL消息后,会跳到下面这个函数中
           CMyScrollBar::VScroll(UINT nSBCode, UINT nPos)

         总结:两个消息的宏声明不一样            
BEGIN_MESSAGE_MAP(CMyScrollBar, CScrollBar)
	//{{AFX_MSG_MAP(CMyScrollBar)
	ON_WM_VSCROLL()      //普通消息
	ON_WM_VSCROLL_REFLECT()  //反射消息,由控件自身处理
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

      f. 
在MyDialog.h中添加垂直滚动条,绑定一个变量

                CMyScrollBar   m_srcrolbar;

      g.   在CMyDialog中OnInitDialog函数中初始化上面的变量           

	int i_scroMax = 100;
	m_scrolbar.SetScrollRange(0,i_scroMax);
	m_scrolbar.SetScrollPos(50);

      h.  在CMyDialog类中响应WM_VSROLL消息响应

         

         
void CMyDialog::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	int pos,Minpos=0,Maxpos=0;
	pos = m_scrolbar.GetScrollPos();
	m_scrolbar.GetScrollRange(&Minpos,&Maxpos);
	switch( nSBCode )
	{
	case SB_LINEUP:
		if( pos > Minpos )
			pos -= INT_SBLINEUP;
		break;

	case SB_LINEDOWN:
		if( pos < Maxpos )
			pos += INT_SBLINEDOWN;
		break;

	case SB_PAGEUP:
		if( pos-INT_SBPAGEUP > Minpos )
			pos -= INT_SBPAGEUP;
		else
			pos = Minpos;
		break;

	case SB_PAGEDOWN:
		if( pos+INT_SBPAGEDOWN < Maxpos )
			pos += INT_SBPAGEDOWN;
		else
			pos = Maxpos;
		break;

	case SB_THUMBPOSITION:
		pos = nPos;
		break;

	}
	m_scrolbar.SetScrollPos(pos,TRUE);
	CDialogEx::OnVScroll(nSBCode, nPos, pScrollBar);
}

           运行发现m_srcolbar对象对应的控件可以正常的运行。因为这个OnVscroll函数中的代码是针对m_srcolbar对象设计的,故其可以正确运行。


     J.  上面的代码看起来很不和谐,有个办法能很好的解决这个问题,就是让绑定控件的变量m_Vscrollbar的类Child自己现实“WM_SCROLL”消息响应函数Child::OnVScroll函数,其父窗体类CFatherDlg也实现“WM_SCROLL”消息响应函数CFatherDlg::OnVScroll,然后用如下方式调用:

        Mark:20131215,(VC6/VS2010环境下调试)此函数被调用了两次,难以理解!即使为空函数体也是这种情况,求解!  

//Mark:20131215
void CFatherDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{

	// TODO: 在此添加消息处理程序代码和/或调用默认值
	if( pScrollBar->GetDlgCtrlID() == m_Vscrollbar.GetDlgCtrlID()) //如果消息对应的控件ID号是我要处理的控件则进行对应处理
        {
           m_Vscrollbar.OnVScroll(nSBCode,nPos,pScrollBar);    
        } 
       //这样就可以针对控件的ID号分别控制多个垂直滚动条,而达到互不干扰、代码思路清晰的好处

CDialogEx::OnVScroll(nSBCode, nPos, pScrollBar);
}

         注意:上面的m_Vscrollbar对象的OnVscroll函数一定要声明成public访问权限,用ClassWizard添加的是Protected访问权限,可以自己手动改过来。

     

3、总结

      如果要控件对应的对象自己处理一个消息,那么控件类自己必须实现“=WM_XXXX”反射响应函数;如果让控件的拥有者相对应的对象处理这个消息,那么应该在改对象的类中实现“WM_XXX”普通响应函数,并针对这个控件绑定的对象设计代码。














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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值