【安富莱二代示波器教程】第7章 示波器设计—波形滑动浏览
第7章 示波器设计—波形滑动浏览
类似手机的滑动功能用在示波器上还是比较实用的,可以用来调节波形位置和滑动浏览波形的存储记录。
7.1 滑动基础知识
7.2 滑动基础知识总结
7.3 滑动功能在窗口上的实现
7.4 总结
7.1 滑动基础知识
滑动的实现是基于emWin提供的Motion功能。在emWin的官方手册中对这部分功能讲解的比较少,但是仍然需要大家去读一下,有一个大概的了解。
7.2 滑动基础知识总结
望大家务必看了emWin官方手册中Motion章节的内容,这里将这些知识点做个汇总,方便大家后面使用。
WM_MOTION_Enable() 使能motion
WM_MOTION_SetMoveable() 使能窗口X方向或者Y方向的Motion
WM_MOTION_SetMovement() 设置窗口以指定的速度移动一段距离。
=================
WM_MOTION_SetDeceleration() 设置窗口减速度
WM_MOTION_SetSpeed() 设置窗口的移动速度。
WM_MOTION_SetMotion() 设置初始速度和加速度。等同于上面两个函数之和
=======================
WM_MOTION_SetDefaultPeriod()
设置指针输入设备(触摸,鼠标,键盘等)等释放后,减速度默认持续的时间。
1、如果窗口在移动中,将减速,直到停止运行。
2、如果窗口没有移动,但是使能了snap功能,那么窗口会在设置的时间内移动到下一个栅格内。
3、如果窗口在移动,且使能了snap功能,那么窗口会减速运动直到停止在最近的一个栅格上。
上面的这些函数都是独立的操作Motion功能,而二代示波器中使用Motion功能是基于窗口的,其实就是把上面这些函数的功能在窗口上实现。下面我们就讲解二代示波器的Motion功能实现。
7.3 滑动功能在窗口上的实现
我们这里以二代示波器的滑动功能实现过程为例,给大家做个说明。
第1步:使能滑动,设置周期。
WM_MOTION_Enable(1); /* 使能滑动 */ WM_MOTION_SetDefaultPeriod(100); /* 设置滑动周期 */
第2步:创建一个透明的窗口,正好覆盖600*400的波形显示区。
hMotion = WM_CreateWindowAsChild(40, 40, 600, 400, WM_HBKWIN, WM_CF_MOTION_Y | WM_CF_SHOW | WM_CF_HASTRANS, _cbMotion, sizeof(pPara)); WM_SetUserData(hMotion, &pPara, sizeof(pPara));
函数里面的标志WM_CF_MOTION_Y | WM_CF_SHOW | WM_CF_HASTRANS比较重要,滑动标志既可以在这里设置,也可以在窗口回调函数的WM_MOTION消息里面设置。
WM_CF_MOTION_Y:表示窗口支持垂直滑动。
WM_CF_MOTION_X:表示窗口支持水平滑动(在窗口回调里面进行了设置)。
WM_CF_HASTRANS:表示窗口透明,这个标志不要忘记设置,这样使用滑动功能的时候对示波器显示区没有任何影响。
第3步:也是最后一步,滑动窗口的回调函数。
源代码是如下这样的:
/* ********************************************************************************************************* * 函 数 名: _cbMotion * 功能说明: Motion窗口的回调函数,主要是桌面图标的滑动处理 * 形 参: pMsg WM_MESSAGE类型指针变量 * 返 回 值: 无 ********************************************************************************************************* */ static void _cbMotion(WM_MESSAGE * pMsg) { WM_MOTION_INFO * pInfo; WM_HWIN hWin = pMsg->hWin; PARA * pPara; switch (pMsg->MsgId) { case WM_MOTION: WM_GetUserData(hWin, &pPara, sizeof(pPara)); pInfo = (WM_MOTION_INFO *)pMsg->Data.p; switch (pInfo->Cmd) { /* Motion功能初始化,设置X方向和Y方向都支持滑动 */ case WM_MOTION_INIT: pInfo->Flags = WM_CF_MOTION_X | WM_CF_MOTION_Y | WM_MOTION_MANAGE_BY_WINDOW; pInfo->SnapY = 1; pInfo->SnapX = 1; break; case WM_MOTION_MOVE: pPara->FinalMove = pInfo->FinalMove; /* Y轴方向,上下滑动 */ if(g_Flag->ucMotionXY == 0) { if((pInfo->pState->Pressed == 1)&&(pInfo->pState->x <= 340)) { pPara->iCH1Pos += pInfo->dy; if(pPara->iCH1Pos >= 440) { pPara->iCH1Pos = 440; } if(pPara->iCH1Pos <= 40) { pPara->iCH1Pos = 40; } g_DSO1->usRefPos = pPara->iCH1Pos; } else if((pInfo->pState->Pressed == 1)&&(pInfo->pState->x > 340)) { pPara->iCH2Pos += pInfo->dy; if(pPara->iCH2Pos >= 440) { pPara->iCH2Pos = 440; } if(pPara->iCH2Pos <= 40) { pPara->iCH2Pos = 40; } g_DSO2->usRefPos = pPara->iCH2Pos; } WM_InvalidateArea(&rRefPos); } /* X轴方向,左右滑动 */ else { if(pInfo->pState->Pressed == 1) { g_DSO1->sCurTriStep -= pInfo->dx; } if(TriggerFlag == 0) { } else { if(g_DSO1->sCurTriStep <= -724) { g_DSO1->sCurTriStep = -724; } if(g_DSO1->sCurTriStep >= 724) { g_DSO1->sCurTriStep = 724; } TriggerFlag = 2; } WM_InvalidateArea(&rTrigPos); } /* 更新当前的数据位置的箭头 */ g_Flag->ucWaveRefresh = 1; break; case WM_MOTION_GETPOS: pInfo->yPos = pPara->iCH1Pos; //pInfo->xPos = pPara->iCH1Pos; break; } break; } }
为了方便看这个函数实现的功能,这里将其进一步简化成如下这样:
static void _cbMotion(WM_MESSAGE * pMsg) { WM_MOTION_INFO * pInfo; WM_HWIN hWin = pMsg->hWin; PARA * pPara; switch (pMsg->MsgId) { case WM_MOTION: WM_GetUserData(hWin, &pPara, sizeof(pPara)); pInfo = (WM_MOTION_INFO *)pMsg->Data.p; switch (pInfo->Cmd) { /* Motion功能初始化,设置X方向和Y方向都支持滑动 */ case WM_MOTION_INIT: //-----------(1) pInfo->Flags = WM_CF_MOTION_X | WM_CF_MOTION_Y | WM_MOTION_MANAGE_BY_WINDOW; pInfo->SnapY = 1; pInfo->SnapX = 1; break; case WM_MOTION_MOVE: //-----------(2) pPara->FinalMove = pInfo->FinalMove; /* Y轴方向,上下滑动 */ if(g_Flag->ucMotionXY == 0) { if(pInfo->pState->Pressed == 1) { } } /* X轴方向,左右滑动 */ else { if(pInfo->pState->Pressed == 1) { } } /* 更新当前的数据位置的箭头 */ g_Flag->ucWaveRefresh = 1; break; case WM_MOTION_GETPOS: //-----------(3) pInfo->yPos = pPara->iCH1Pos; //pInfo->xPos = pPara->iCH1Pos; break; } break; } }
滑动功能实现的关键就在这个WM_MOTION消息里面。
1、WM_MOTION_INIT消息
在初始化消息里面设置pInfo->Flags来使能水平滑动和垂直滑动,并且通过标志WM_MOTION_MANAGE_BY_WINDOW使能窗口管理器来管理Motion功能。标志pInfo->SnapY和pInfo->SnapX是用来设置滑动停止后的栅格区域,详情看7.2小节中函数WM_MOTION_SetDefaultPeriod的作用说明。
2、WM_MOTION_MOVE消息
这个消息在二代示波器中的使用比较简单,主要是判断是否按下,然后根据按下的位置设置波形的水平或者上下移动即可。当前按下的位置在参数pInfo->pState->x和pInfo->pState->y里面。实际的波形更新是通过设置标志g_Flag->ucWaveRefresh = 1实现的。
3、WM_MOTION_GETPOS消息
这个消息未用到,用于获取按下的位置。
7.4 总结
关于滑动的实现,关键的知识点就这么多,需要大家实际操作下,有个深入的认识。