MFC中的NMHDR结构体和NMUPDOWN结构体
建立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。
所以不能理解成员变量值传递,而是要从内存上去理解。成员变量只是一个代号而已。
还是不理解的话,可以把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);
MFC中的NMHDR结构体和NMUPDOWN结构体的更多相关文章
- ABAP中不修改内表参照的结构,给内表/结构体增加字段
Situation: DATA: itab TYPE STANDARD TABLE OF zsrsodtla_stru1, wa_itab TYPE zsrsodtla_str ...
- matlab学习笔记12_2创建结构体数组,访问标量结构体,访问非标量结构体数组的属性,访问嵌套结构体中的数据,访问非标量结构体数组中多个元素的字段
一起来学matlab-matlab学习笔记12 12_2 结构体 创建结构体数组,访问标量结构体,访问非标量结构体数组的属性,访问嵌套结构体中的数据,访问非标量结构体数组中多个元素的字段 觉得有用的话 ...
- MFC中显示 .bmp格式的位图
最近在看VisualC++ 图像处理的书籍,表示一直在从基础做起,今天就记录一个简单功能的实现,显示.bmp格式的位图. 首先需要理解的是窗口创建的过程包括两个步骤:首先擦除窗口的背景,然后在对窗口进 ...
- MFC中树控件CTreeCtrl的用法
树形控件可以用于树形的结构,其中有一个根接点(Root)然后下面有许多子结点,而每个子结点上有允许有一个或多个或没有子结点.MFC中使用CTreeCtrl类来封装树形控件的各种操作.通过调用 BOOL ...
- MFC中的CString类使用方法指南
MFC中的CString类使用方法指南 原文出处:codeproject:CString Management [禾路:这是一篇比较老的资料了,但是对于MFC的程序设计很有帮助.我们在MFC中使用字符 ...
- MFC 中的设计模式分析
MFC 中的设计模式分析 最近在学习设计模式,突然想到MFC里面其实也包含有设计模式的原理,于是分析了一下,做一个笔记,网上也找了一些资料,在此一并感谢. 创建型模式 单例模式(Singleton P ...
- GDI+学习笔记(九)带插件的排序算法演示器(MFC中的GDI+实例)
带插件的排序算法演示器 请尊重本人的工作成果,转载请留言.并说明转载地址,谢谢. 地址例如以下: http://blog.csdn.net/fukainankai/article/details/27 ...
- MFC中CString转换成char数组的问题
由于结构体中用到联合体(联合体需要确定分配内存分配大小)或其它因素,需要用char数组来保存字符串,但是在MFC中一般都是用CString来存放字条串.关于它们之间的转换,在VS2008中有时会出现异 ...
- 在MFC中使用Cstring
此文介绍了关于MFC使用CString的资料,可一参考一下. 转自于VC知识库:http://www.vckbase.com/index.php/wv/829 通过阅读本文你可以学习如何有效地使用 C ...
随机推荐
- JavaScript高级程序设计:第三章
基本概念 一.语法: 1.区分大小写: 2.标识符:指变量.函数.属性的名字,或者函数的参数.标识符可以是按照下列格式规则组合起来的一个或多个字符: (1)第一个字符必须是一个字母.下划线(_).或者 ...
- LeetCode OJ 223.Rectangle Area
Find the total area covered by two rectilinear rectangles in a 2D plane. Each rectangle is defined b ...
- 解决ORA-00904: invalid identifier标识符无效
方法/步骤 1 大部分情况下,此错误是由于引用了不存在的列名导致的.比如select name from Studtent 当studeng表中无name列时,系统就会报此错误. 2 解决思路是,确定 ...
- BZOJ3036绿豆蛙的归宿
BZOJ3036绿豆蛙的归宿 锲下陟凝 褰宓万 郝瓦痕膳 叶诙摞 А知π剧 椐猊∫距 屠缲佗 ゲ蕖揪 俜欧彖鹤 磲砩ほ #琛扶 觅电闸ス 捆鳢げ 浜窠 魂睨"烁 蕞滗浼 洒ヂ跪 ...
- linuxmint卸载软件
删除你已经卸载掉的软件包的命令为 sudo apt-get autoclean 还有一类软件包,我们每个人都应该删除,那就是你已经卸载了,但是一些只有它依赖而别的软件包都不需要的软件包还留在你的系统里 ...
- 转 12C 连接CDB和PDB
来源:David Dai -- Focus on Oracle 连接到CDB 和普通实例一样的连接. 指定ORACLE_SID 以后可以使用OS认证,也可以使用密码进行连接. [oracle@Ora1 ...
- 什么是dtd文件,为什么需要
DTD为英文Document Type Definition,中文意思为“文档类定义”.DTD肩负着两重任务:一方面它帮助你编写合法的代码,另一方面它让浏览器正确地显示器代码.也许你会问它们居然有这样 ...
- combo扩展:禁止手工改变输入框的值
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...
- java 数据结构 队列的实现
java 数据结构队列的代码实现,可以简单的进行入队列和出队列的操作 /** * java数据结构之队列的实现 * 2016/4/27 **/ package cn.Link; import java ...
- 2015年5月9日 student information management system
/*大作业SIMS*///头文件 #ifndef __FUNC_C__ #define __FUNC_C__ #include <stdio.h> #include <stdlib. ...