WinCE下EM9X60单色LCD屏菜单界面设计方案

 2010-1-18              

        低成本的单色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索取相关代码。