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


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

     1 void CSpinDlg::OnDeltaposSpin1(NMHDR* pNMHDR, LRESULT* pResult)
     2 
     3 {
     4 
     5   NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
     6 
     7   // TODO: Add your control notification handler code here
     8 
     9  
    10 
    11       *pResult = 0;
    12 
    13 }

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

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

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

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

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

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

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

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

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

    从而获得该控件的句柄。

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

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

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

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

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

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

     1 void CSpinDlg::OnDeltaposSpin1(NMHDR* pNMHDR, LRESULT* pResult) 
     2 {
     3     NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
     4     HWND hwnd;
     5 
     6     hwnd = ::GetDlgItem(m_hWnd,IDC_SPIN1);
     7 
     8     if ((pNMHDR->idFrom == IDC_SPIN1) && (pNMHDR->code == UDN_DELTAPOS) && (pNMHDR->hwndFrom == hwnd))
     9     {
    10         MessageBox("Spin down","Spin",MB_OK);  //写法1
    11     }
    12 
    13     if ((pNMUpDown->hdr.idFrom == IDC_SPIN1)&& (pNMUpDown->hdr.code == UDN_DELTAPOS) && (pNMUpDown->hdr.hwndFrom == hwnd))
    14     {
    15         MessageBox("Spin down too","Spin",MB_OK); //写法2
    16     }
    17 
    18     if (pNMUpDown->iPos == 8)
    19     {
    20         MessageBox("当前值是8","Spin",MB_OK);
    21     }
    22 
    23     if(pNMUpDown->iDelta == 1)
    24     {
    25         MessageBox("加1","Spin",MB_OK);
    26     }
    27 
    28     if(pNMUpDown->iDelta == -1)
    29     {
    30         MessageBox("减-1","Spin",MB_OK);
    31     }
    32 
    33     *pResult = 0;
    34 }

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

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

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

    首先看个例1

     1 #include <iostream>
     2 using namespace std;
     3 
     4 typedef struct _A
     5 {
     6     int hwnd;
     7     int idFrom;
     8     int code;
     9 }A;
    10 
    11 typedef struct _B
    12 {
    13     A hdr;
    14     int iPos;
    15     int iDelta;
    16 }B;
    17 
    18 int main(void)
    19 {
    20     A a;
    21     A *pa;  //定义结构体指针变量
    22     pa = &a;
    23     pa->hwnd = 1;
    24     pa->idFrom = 10;
    25     pa->code = 100;
    26 
    27 
    28     B *b = (B *)pa;  //强制转换赋b,指针b和pa就指向同一块内存
    29     
    30     cout<<b->hdr.hwnd<<endl;
    31     cout<<b->hdr.idFrom<<endl;
    32     cout<<b->hdr.code<<endl;
    33 
    34     cout<<b->iPos<<endl;
    35     cout<<b->iDelta<<endl;
    36     
    37     return 0;
    38 }

    输出结果:

    1

    10

    100

    1245120

    4332217

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

    在看个例2

     1 #include <iostream>
     2 using namespace std;
     3 
     4 typedef struct _A
     5 {
     6     int hwnd;
     7     int idFrom;
     8     int code;
     9 }A;
    10 
    11 typedef struct _B
    12 {
    13     int iPos;
    14     int iDelta;
    15     A hdr;  //位置放在最后
    16 }B;
    17 
    18 int main(void)
    19 {
    20     A a;
    21     A *pa;  //定义结构体指针变量
    22     pa = &a;
    23     pa->hwnd = 1;
    24     pa->idFrom = 10;
    25     pa->code = 100;
    26 
    27 
    28     B *b = (B *)pa;  //强制转换赋b,指针b和pa就指向同一块内存
    29     
    30     cout<<b->hdr.hwnd<<endl;
    31     cout<<b->hdr.idFrom<<endl;
    32     cout<<b->hdr.code<<endl;
    33 
    34     cout<<b->iPos<<endl;
    35     cout<<b->iDelta<<endl;
    36     
    37     return 0;
    38 }

    输出结果:

    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。

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

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

    1 cout<<"hwnd地址"<<&a.hwnd<<" "<<a.hwnd<<endl;
    2 cout<<"idFrom地址"<<&a.idFrom<<" "<<a.idFrom<<endl;
    3 cout<<"code地址"<<&a.code<<" "<<a.code<<endl;
    4 ...
    5 ...

     备注:

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

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

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

      如下,步长为2

    1     UDACCEL udaccel;
    2     udaccel.nInc = 2;  //步长为2的增或减
    3     udaccel.nSec = 0;  //在改变前所等待的秒数
    4 
    5     Spin1->SetAccel(1,&udaccel);
  • 相关阅读:
    [LeetCode] 294. Flip Game II 翻转游戏之二
    [LeetCode] 293. Flip Game 翻转游戏
    [LeetCode] 266. Palindrome Permutation 回文全排列
    [LeetCode] 288. Unique Word Abbreviation 独特的单词缩写
    [LeetCode] Self Crossing 自交
    [LeetCode] 281. Zigzag Iterator 之字形迭代器
    [LeetCode] 251. Flatten 2D Vector 压平二维向量
    [LeetCode] 250. Count Univalue Subtrees 计数相同值子树的个数
    [LeetCode] 249. Group Shifted Strings 群组偏移字符串
    [LeetCode] 248. Strobogrammatic Number III 对称数之三
  • 原文地址:https://www.cnblogs.com/wen2376/p/3791666.html
Copyright © 2020-2023  润新知