低成本的单色LCD在工业领域应用非常广泛,英创公司提供的基于WinCE平台的EM9X60系列板卡均支持外接单色LCD屏,目前应用得比较多的规格包括有LCD320X240、LCD240X128、LCD128X64等。在实际应用中有许多对于菜单界面操作的需求,由于EM9X60系列板没有支持标准的Windows桌面显示,因此应用程序无法直接利用WindowsCE的窗口界面、或者基于MFC的对话框作为应用程序的操作界面,而是需要客户根据应用的具体要求自行构建菜单界面,本文将重点介绍这方面的内容。
基于菜单界面操作过程实质一个简单的交互式操作,需要实时响应键盘消息、定时消息等。WinCE操作系统内部具备有完善的消息处理机制,来实现应用请求消息的实时响应。因此本案例是一个具有Windows风格的应用例程,通过窗口的消息传递来实现对于键盘、定时任务的实时响应,从而实现对于菜单界面的操作。
下面分两个部分来介绍该例程:
1、应用程序框架
在Windows下进行窗口应用程序编程的优点,程序只对操作系统发给它的通知进行响应,比如收到键盘被按下、定时任务等,而不需要应用程序不断地查询窗口的请求输入。在支持单色LCD的WinCE系统下也是如此,操作系统在有输入发生时会通知应用程序,操作系统是通过发送消息到应用程序窗口的方式来完成这个通知,虽然该“应用程序窗口”无法正常显示,但是可以通过它来完成消息的传递。本例程采用传统的Windows窗口应用程序编程的框架,以方便实现对于外界请求输入的响应,从而实现在单色LCD上菜单界面的操作显示。
在该程序例程中WinMain(…)函数也是按照窗口应用程序的过程,首先进行初始化操作,包括对于LCD屏的初始化、菜单界面的初始化操作、加载矩阵键盘驱动等操作;然后是创建窗口;再进入消息循环。如下图所示:
// LCD初始化操作以及加载缺省的菜单界面
i1 = LCD_Init( LCD_12864 );
LCD_LoadSmallFnt( );
LCD_SetMode( 1 ); // set to XOR mode
status = MenuManager.LoadMenu( );
if( status < 0 ) return status;
MenuManager.Show( );
// 激活基于EM9x60板卡ISA的矩阵键盘驱动
hDevice = ActivateDevice( TEXT('Drivers\\isa_keypad'), 0);
// 初始化本程序实例,主要是创建窗口等工作
hwndMain = InitInstance( hInstance, lpCmdLine, nCmdShow );
if( hwndMain == 0 )
return 0x10; // init fail!
// 设置定时器的时间间隔为2秒
SetTimer( hwndMain, 1, 2000, NULL );
// 应用程序消息循环
while( GetMessage( &msg, NULL, 0, 0 ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
KillTimer( hwndMain, 1 );
LCD_UnLoadSmallFnt( );
其中的消息循环为主线程,循环很简单,调用GetMessage函数,从应用程序的消息队列中取得一条来自系统的消息,如果没有消息到来,这个函数就是处于等待状态,相当于这个应用主线程就被阻塞直到消息到来。
菜单例程中响应的系统消息包括:键盘消息(WM_KEYUP)和定时消息(WM_TIMER),WinCE和Windows标准系统一样使用了相同的键盘消息处理方式。当一个键按下时,通常是以WM_KEYDOWN消息起始,如果按下的键代表一个字符,比如一个字母或数字,在WM_KEYDOWN之后还会发送一个WM_CHAR消息,当键被释放时,最终的WM_KEYUP消息被发送,在这些消息的参数wParam指示了按下键的虚拟键值。为了简化程序,在此例程中对于按键的响应,是等到按键释放的时候,也就是说应用程序只响应WM_KEYUP消息。定时消息则可以通过函数SetTimer( … )来实现,该函数同时也设置了定时事件、以及定时间隔。
消息的响应是通过定义MainMessage表格,将消息值和消息处理例程函数关联起来。如:
const struct decodeUINT MainMessages[] =
{
{ WM_KEYUP, DoKeysMain },
{ WM_TIMER, DoTimerMain },
{ WM_DESTROY, DoDestroyMain }
};
// 键盘消息WM_KEYUP ..处理函数
LRESULT DoKeysMain( HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam )
{
switch( wParam )
{
case 0x33: // 移动键
MenuManager.Key_SHIFT( );
break;
case 0x36: // 确认键
MenuManager.Key_ENTER( );
break;
}
return 0;
}
// 定时消息WM_TIMER处理函数
LRESULT DoTimerMain( HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam )
{
MenuManager.Update( );
return 0;
}
2、菜单界面设计
在本例程中主要是针对一个基于LCD128X64显示终端所设计的二级菜单显示界面,功能键有两个:移动键(Key_Shift)和确认键(Key_Enter),通过移动键选择菜单项,确认键来进入下一级,或者返回上一级菜单。
菜单的显示和管理是通过C++方式来实现,Class Item定义菜单中各个菜单项的显示特性以及操作特性;Class Menu定义了菜单的特性,其中包含又对于菜单中各个菜单项管理的功能;Class MenuManager是一个菜单管理类,这个类实现了对于各个菜单的管理和操作特性,相当于一个人机交互界面的功能。它们定义分别在 Item.h Menu.h文件中。
为了增加菜单设计的灵活性,对于各个菜单界面的显示内容采用了读取配置文件的方式,即在配置文件中定义各个菜单的显示名称和显示位置,如:
// item的类型 显示名称 X位置 Y位置 下一级菜单名称
item=301 终端参数 0 0 MENU1
item=301 实时数据 0 16 MENU2
item=301 终端状态 0 32 MENU3
item=301 显示配置 0 48 MENU4
item=301 扩展菜单 64 0 MENU5
item=301 扩展菜单 64 16 MENU6
item=301 扩展菜单 64 32 MENU7
item=301 扩展菜单 64 48 MENU8
根据该配置文件所形成的菜单如下:
本文中所介绍的例程仅仅适用于英创EM9X60系列板卡,均有源码提供。感兴趣的客户可以发邮件到公司技术支持邮箱support@emtronix.com索取相关代码。
成都英创信息技术有限公司 028-8618 0660