C++基础(十五)C++ afx_msg消息处理详细分析:BEGIN_MESSAGE_MAP 、ON_WM_TIMER(&ReduceDB::OnTimer) 、ON_MESSAGE

一、简介

       最近用到了获取,串口消息,消息处理主要用到了微软的<afxwin.h>头文件的afx_msg类。先调研一番消息处理函数,然后举例说明。那么我们分为下面几个步骤讨论MFC中afx_msg定义的消息。

步骤一:

         在头文件KGenDel.h中,用afx_msg定义消息及其格式

步骤二:

        在KGenDel.cpp中,使用 BEGIN_MESSAGE_MAP 启动消息及其格式,它的具体格式如下:

BEGIN_MESSAGE_MAP(KGenDel, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
        ON_WM_TIMER(&ReduceDB::OnTimer)  //启动定时器
	ON_MESSAGE(WM_COMM_RXCHAR, &KGenDel::OnComm)//单字节响应函数
	ON_BN_CLICKED(IDC_BUTTON1, &KGenDel::OnBnClickedButton1)
	ON_WM_CLOSE()
END_MESSAGE_MAP()

稍后我会解释每一行的代码。 

步骤三:

          在KGenDel.cpp中,对消息函数KGenDel::OnComm 和 ReduceDB::OnTimer进行实现

二、afx_msg定义消息及其格式

     afx_msg主要在MFC中应用,比较古老了。消息函数主要用到afx_msg关键字来定义。这几篇博客完美的解析了afx_msg关键字。

https://blog.csdn.net/holandstone/article/details/7452384

https://www.cnblogs.com/linkzijun/p/6196165.html

     那么,我把我项目中的KGenDel.h文件拿出来,分析下afx_msg及其格式。

KGenDel.h:

class KGenDel : public CDialogEx
{
    public:
	    KGenDel(CWnd* pParent = NULL);   // 标准构造函数
	    virtual ~KGenDel();
        //nIDEvent:是触发器的名字,启动定时器,间隔发指令给串口
        afx_msg void OnTimer(UINT_PTR  nIDEvent); 
        //接收来自串口的指令。
        afx_msg LRESULT OnComm(WPARAM ch, LPARAM port);
}

三、BEGIN_MESSAGE_MAP 启动消息及其格式

https://www.cnblogs.com/liangjq/p/4462926.html

https://blog.csdn.net/luoti784600/article/details/10070939

参看https://www.cnblogs.com/linkzijun/p/6196165.html,得到了在MFC界面中,按钮的点击消息,使得界面显示的结果得以改变,它提供的BEGIN_MESSAGE_MAP 格式如下:

而我的KGenDel.cpp用到的格式如下:

BEGIN_MESSAGE_MAP(KGenDel, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
        ON_WM_TIMER(&ReduceDB::OnTimer)  //启动定时器
	ON_MESSAGE(WM_COMM_RXCHAR, &KGenDel::OnComm)//单字节响应函数
	ON_BN_CLICKED(IDC_BUTTON1, &KGenDel::OnBnClickedButton1)
	ON_WM_CLOSE()
END_MESSAGE_MAP()

 那么你可以看到,格式大致相同。基类CWnd与基类CDialogEx不同,消息类型也有很多种,比如CHANGE、CLICKED、TIMER不同。

那么来解说下这样的结构。

1、BEGIN_MESSAGE_MAP(参数1,参数2):表示开启消息映射,参数1为该类的类名,参数2为该类基类的类名。

 https://www.cnblogs.com/liangjq/p/4462926.html

BEGIN_MESSAGE_MAP(CChileView, Cwnd)——CChileView.cpp类是继承Cwnd类,用来操作窗体。

BEGIN_MESSAGE_MAP(KGenDel, CDialogEx)——KGenDel.cpp类是继承CDialogEx类,用来操作对话框。

2、END_MESSAGE_MAP()——结束消息映射

3、ON_MESSAGE(参数1,参数2):参数1为响应的消息,参数2为该消息对应的处理的函数名。

ON_MESSAGE(WM_COMM_RXCHAR, &KGenDel::OnComm)—— 表示开启消息响应函数,一旦受到串口来的消息WM_COMM_RXCHAR(注意啊,WM_COMM_RXCHAR是一个消息,它由串口类触发),那么响应函数KGenDel::OnComm。这行代码就是用来接收串口传回来的指令。

4、ON_BN_CLICKED(参数1,参数2)—— 单击控件后,响应此消息。

5、ON_WM_TIMER(&ReduceDB::OnTimer) ——定时器。

四、消息函数KGenDel::OnComm 和 ReduceDB::OnTimer进行实现:工程中应用举例

1、.h文件中定义消息

LRESULT——表示长整数(默认)

WPARAM——表示长整数(默认)

LPARAM——表示短整数(默认)

ch——形参

port——形参

2、启动消息

BEGIN_MESSAGE_MAP(KGenDel, CDialogEx)——启动消息,KGenDel表示类。CDialogEx是系统生成了不知道啥意思。

ON_MESSAGE(WM_COMM_RXCHAR, &KGenDel::OnComm)——通过WM_COMM_RXCHAR与串口关联起来,一旦接收串口类的指令,则响应消息OnComm。事件上,OnComm是KGenDel.cpp的函数。

END_MESSAGE_MAP()——关闭

3、 消息函数的实现

定时器发消息给串口:

void KGenDel::OnTimer(UINT_PTR nIDEvent)
 {
	switch (nIDEvent)
	{
	case 1:
		Exposure();//检测高压命令
		//RetrErrorLog();//检索高压错误日志
		//ErrorParameters();//检查曝光参数错误
		//RetrieveExposure();//检索曝光结果
		break;
	default:
		break;
	}
}

注意啊, nIDEvent表示定时器的ID,因为一个系统可能要用多个定时器,所以,必须设置定时器的ID。

当ID = 1,那么我就启动第一个定时器,来处理第一件事情。

当ID = 2,那么我就启动第2个定时器,来处理第2件事情。

当ID = 3,那么我就启动第3个定时器,来处理第3件事情。

......

好了,那么,请问如何设置定时器?微软给我提供了SetTimer定时器:

int TimerID = 1;
SetTimer(TimerID, 200, NULL); 

200ms表示定时器的时间:每隔200ms让它执行Exposure()函数。

接收来自串口的消息:

//消息响应函数:
LRESULT KGenDel::OnComm(WPARAM ch, LPARAM port)
{
		if (16 > ch)
		{
			str.Format(_T("0%X "), ch);
		}
		else
		{
			str.Format(_T("%X "), ch);
		}
		m_RecvBuf += str;
		data[cnt] = ch;
		cnt++;
		
		BYTE *p = (BYTE*)&data;
		if (136 == data[12] && 240 == data[0]) //函数发送短命令
		{
			m_cLogger.WriteDebugLog("KGenDel::OnComm: 命令解析开始 ", 200);
			m_cLogger.WriteDebugLog("KGenDel:: OnComm:  " + m_RecvBuf, 200);
			m_RecvBuf.ReleaseBuffer();      //第一步清空函数内存,保证存取上一次数据
			m_RecvBuf.Empty();              //第二步清空函数内存,强制设置为空
			m_cLogger.WriteDebugLog("KGenDel::OnComm:  命令结束", 200);
		}
		if (136 == data[18] && 240 == data[0]) //函数发送长命令
		{
			m_cLogger.WriteDebugLog("KGenDel::OnComm: 命令解析开始 ", 200);
			m_cLogger.WriteDebugLog("KGenDel:: OnComm:  " + m_RecvBuf, 200);
			m_RecvBuf.ReleaseBuffer();
			m_RecvBuf.Empty();  
			m_cLogger.WriteDebugLog("KGenDel::OnComm:  命令结束", 200);
		}
		OnComm1();

	return 0;
}

4、串口类中,包含了WM_COMM_RXCHAR(虽然不知道串口怎么关联消息)

 


版权声明:本文为xpj8888原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。