MFC中的NMHDR结构体和NMUPDOWN结构体

时间:2024-01-01 23:28:53

建立spin控件,创建UDN_DELTAPOS一个消息函数后:

 void CSpinDlg::OnDeltaposSpin1(NMHDR* pNMHDR, LRESULT* pResult)

 {

   NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;

   // TODO: Add your control notification handler code here

       *pResult = ;

 }

问题1:参数NMHDR* pNMHDR, LRESULT* pResult干嘛用?

NMHDR结构体,查看MSDN,经过应用,其意义如下

 typedef struct tagNMHDR {
HWND hwndFrom; //控件的句柄
UINT idFrom; //控件的ID号
UINT code; //通知代码,即消息类型
} NMHDR;
ID号很好知道,创建的时候就有分配了一个ID,如IDC_SPIN1
通知代码,既消息类型,也可以知道该消息是UDN_DELTAPOS

控件句柄呢,马上开始想到经常用的CWnd* GetDlgItem( int nID ),然而该函数返回的是一个指针对象,并不是句柄。
可以用SDK 平台函数:返回是指定控件的句柄
 HWND GetDlgItem(
HWND hDlg, // handle of dialog box 对话框窗口句柄
int nIDDlgItem // identifier of control 控件标示符,即ID
);

可以执行下代码,验证是否正确
 void CSpinDlg::OnDeltaposSpin1(NMHDR* pNMHDR, LRESULT* pResult)
{
  NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
  HWND hwnd;   hwnd = ::GetDlgItem(m_hWnd,IDC_SPIN1); //注意写法 m_hWnd是对话框窗口句柄,父窗口
  if ((pNMHDR->idFrom == IDC_SPIN1) && (pNMHDR->code == UDN_DELTAPOS) && (pNMHDR->hwndFrom == hwnd))
  {
    MessageBox("Spin down","Spin",MB_OK);
  }   *pResult = ;
}

当你点击Spin按钮时,弹出对话框,提示Spin down,说明是对的。

另一种方式也可以获取控件句柄

     if ((pNMHDR->idFrom == IDC_SPIN1) && (pNMHDR->code == UDN_DELTAPOS) && (pNMHDR->hwndFrom == GetDlgItem(IDC_SPIN1)->m_hWnd/*hwnd*/))
{
MessageBox("Spin down","Spin",MB_OK);
}

m_hWnd是属于CWin的一个成员,而CWnd* GetDlgItem( int nID ) const 返回一个指向CWnd的一个指针,所以就可以利用改指针来引用m_hWnd成员,

从而获得该控件的句柄。

 问题2:NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR; 为什么这样写,目的是干嘛呢?

首先知道NM_UPDOWN是NMUPDOWN结构体名的宏,把pNMHDR强制转化为该类型,该结构体如下

 typedef struct _NM_UPDOWN {
NMHDR hdr; //NMHDR structure that contains additional information about the notification message.
int iPos; //该控件当前值
int iDelta; //用该值确认是往上加,还是往下减
} NMUPDOWN, FAR *LPNMUPDOWN;

在BOOL CSpinDlg::OnInitDialog()函数中加入下面几行代码,进行初始化

 CSpinButtonCtrl *pSpin = (CSpinButtonCtrl *)GetDlgItem(IDC_SPIN1);
// pSpin->SetRange(100, 0); //按上面的箭头是减,按下面的箭头是加
pSpin->SetRange(, ); //按上面的箭头是加,按下面的箭头是减
pSpin->SetBase(); //按十进制方式
pSpin->SetPos(); //把当前值设置为8

然后在void CSpinDlg::OnDeltaposSpin1(NMHDR* pNMHDR, LRESULT* pResult) 加上验证代码

 void CSpinDlg::OnDeltaposSpin1(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
HWND hwnd; hwnd = ::GetDlgItem(m_hWnd,IDC_SPIN1); if ((pNMHDR->idFrom == IDC_SPIN1) && (pNMHDR->code == UDN_DELTAPOS) && (pNMHDR->hwndFrom == hwnd))
{
MessageBox("Spin down","Spin",MB_OK); //写法1
} if ((pNMUpDown->hdr.idFrom == IDC_SPIN1)&& (pNMUpDown->hdr.code == UDN_DELTAPOS) && (pNMUpDown->hdr.hwndFrom == hwnd))
{
MessageBox("Spin down too","Spin",MB_OK); //写法2
} if (pNMUpDown->iPos == )
{
MessageBox("当前值是8","Spin",MB_OK);
} if(pNMUpDown->iDelta == )
{
MessageBox("加1","Spin",MB_OK);
} if(pNMUpDown->iDelta == -)
{
MessageBox("减-1","Spin",MB_OK);
} *pResult = ;
}

可以逐步验证每个成员的意义是否正确,其中写法1和写法2是结果是相同的。

问题3:NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR  

该函数中的两个不同类型结构体,经强制转换赋给另外一个结构体,最终两结构体都占用同快内存吗?还有pNMHDR里的成员会怎么传递呢?

首先看个例1

 #include <iostream>
using namespace std; typedef struct _A
{
int hwnd;
int idFrom;
int code;
}A; typedef struct _B
{
A hdr;
int iPos;
int iDelta;
}B; int main(void)
{
A a;
A *pa; //定义结构体指针变量
pa = &a;
pa->hwnd = ;
pa->idFrom = ;
pa->code = ; B *b = (B *)pa; //强制转换赋b,指针b和pa就指向同一块内存 cout<<b->hdr.hwnd<<endl;
cout<<b->hdr.idFrom<<endl;
cout<<b->hdr.code<<endl; cout<<b->iPos<<endl;
cout<<b->iDelta<<endl; return ;
}

输出结果:

1

10

100

1245120

4332217

例1中经强制转换并赋给b后,b和pa指向同块内存,貌似成员值也赋过来了。最后两行的值由于没初始化,根据不同系统输出不确定的值。

在看个例2

 #include <iostream>
using namespace std; typedef struct _A
{
int hwnd;
int idFrom;
int code;
}A; typedef struct _B
{
int iPos;
int iDelta;
A hdr; //位置放在最后
}B; int main(void)
{
A a;
A *pa; //定义结构体指针变量
pa = &a;
pa->hwnd = ;
pa->idFrom = ;
pa->code = ; B *b = (B *)pa; //强制转换赋b,指针b和pa就指向同一块内存 cout<<b->hdr.hwnd<<endl;
cout<<b->hdr.idFrom<<endl;
cout<<b->hdr.code<<endl; cout<<b->iPos<<endl;
cout<<b->iDelta<<endl; return ;
}

输出结果:

100

1245120

4332217

1

10

例2中,在结构体B中的A hdr;成员放置到最后,其输出结果就有大所不同。

如下简单示意图,假设A结构体定义变量后,内存分配情况:

内存地址        内存中的值

0x00002 ->       1

0x00006 ->      10

0x0000c ->      100

经过强制转换,赋给b后,使b、pa和a三个变量都同时指向同块内存的首地址。结构体变量b分配的内存空间在结构

体变量pa的内存基础上继续分配了0x00010、0x00014两个地址,故结构体变量b的前三个成员变量值就是1、10、100。

所以不能理解成员变量值传递,而是要从内存上去理解。成员变量只是一个代号而已。

MFC中的NMHDR结构体和NMUPDOWN结构体

还是不理解的话,可以把A中的三个成员变量地址打出来,然后把B中的成员变量地址也打出来对比就知道了。

 cout<<"hwnd地址"<<&a.hwnd<<" "<<a.hwnd<<endl;
cout<<"idFrom地址"<<&a.idFrom<<" "<<a.idFrom<<endl;
cout<<"code地址"<<&a.code<<" "<<a.code<<endl;
...
...

备注:

  设置增量步长可以使用SetAccel(int nAccel,UDACCEL* pAccel )函数:

1、参数nAccel表示由pAccel指定的UDACCEL结构的数目.

2、pAccel指向一个UDACCEL结构数组的指针

  如下,步长为2

     UDACCEL udaccel;
udaccel.nInc = ; //步长为2的增或减
udaccel.nSec = ; //在改变前所等待的秒数 Spin1->SetAccel(,&udaccel);