Hello China GUI模块鼠标指针的实现

 在图形系统中,需要通过鼠标指针动态跟踪鼠标的位置,来实现鼠标的点击输入。在Hello China当前版本的实现中,是通过下列一种简单的方式实现的:

1、  RAWIT线程中,实时处理鼠标移动事件(Mouse Move),在鼠标移动事件中,画出鼠标指针;

2、  在画鼠标指针前,首先保存被鼠标图标覆盖的当前屏幕区域,以使得鼠标在更换位置的时候,能够恢复窗口原有位置的信息;

3、  保存鼠标覆盖区域后,再通过画点的方式,把鼠标图形画到屏幕上;

4、  在鼠标移出当前位置的时候,恢复原来保存的屏幕信息。

 

鼠标指针的处理,都是在RAWIT线程中实现的。这样可实现如下功能:

1、  鼠标指针的处理,跟实际应用程序无关,是系统级别的处理。这样即使用于应用程序出现故障,也不会影像鼠标在屏幕上的移动;

2、  鼠标指针是通过Video对象的画点函数(DrawPixel)来实现的。而所有使用GUI功能的应用程序,也都是调用Video对象提供的函数来画出窗口,因此可处理动态屏幕更新的情况:鼠标覆盖住的屏幕位置是动态变化的。比如,鼠标覆盖住了一个不断变化的计数器,在鼠标覆盖期间,计数器的数值已经变化。若鼠标移动开以后,仍然按照鼠标进入的内容恢复屏幕,则会出现内部不一致的问题。解决这个问题的办法,就是通过Video对象,实时更新鼠标位置。每次接收到屏幕更新需求,Video对象首先判断该更新对象是否在鼠标覆盖位置。若不是,则直接更新,否则,需要在更新数据后,同时保存屏幕更新的数据,并再次画出鼠标指针(鼠标指针永远位于所有屏幕内容之上)。

 

下面是Hello China V1.6版本的GUI模块中,鼠标的指针形状:

 

 

鼠标实际上是一个16×16象素的图标,这16×16个象素,并不是都要画出来的,而只是画出需要的一些象素,反映出一个箭头形状即可。因此,采用一个bite数组,来指明这个16×16的方块中,那些象素需要画出。如下:

 

static int MouseMap[16][16] = {

       {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},

       {1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0},

       {1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0},

       {1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0},

       {1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0},

       {1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0},

       {1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0},

       {1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0},

       {1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0},

       {1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0},

       {1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0},

       {1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0},

       {1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0},

       {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},

       {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},

       {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},

};

 

在上面这个二维数组中,只有标志为1的象素点,需要画出。画鼠标指针的代码如下所示:

 

static VOID DrawMouse(__VIDEO* pVideo,int x,int y)

{

       int i,j;

       //Save the rect occupied by mouse first.

       SaveMouseRect(pVideo,x,y);

       for(i = 0;i < 16;i ++)

       {

              if(y + i >= (int)pVideo->dwScreenHeight)

              {

                     break;

              }

              for(j = 0;j < 16;j ++)

              {

                     if(MouseMap[i][j])  //Should draw.

                     {

                            if(x + j >= (int)pVideo->dwScreenWidth)

                            {

                                   break;

                            }

                            DrawPixel(pVideo,x + j,y + i,COLOR_BLACK);

                     }

              }

       }

}

 

在上述代码中,xy是当前鼠标指针的位置,上述代码,以xy坐标为鼠标指针的左上角,画出鼠标指针。该函数在执行前,首先调用SaveMouseRect函数,保存了鼠标矩形所覆盖的屏幕信息,以便后续恢复。SaveMouseRect的代码如下:

 

static VOID SaveMouseRect(__VIDEO* pVideo,int x,int y)

{

       int i,j;

       for(i = 0;i < 16;i ++)

       {

              if(y + i >= (int)pVideo->dwScreenHeight)

              {

                     break;

              }

              for(j = 0;j < 16;j ++)

              {

                     if(x + j >= (int)pVideo->dwScreenWidth)

                     {

                            break;

                     }

                     if(MouseMap[i][j])

                     {

                            MouseRect[i][j] = GetPixel(pVideo,x + j,y + i);

                     }

              }

       }

}

 

上述代码与DrawMouse代码类似,就是根据鼠标位图(MouseMap),来保存特定的屏幕信息,而不是保存整个16×16大小的矩形。

这样在鼠标移动的时候,就很容易实现鼠标指针的移动了:

 

static VOID DoMouseMove(int x,int y)  //x and y is the coordinate of mouse.

{

       static int xppos = 0;  //Previous position of x.

       static int yppos = 0;  //Previous position of y.

       int xpos,ypos;

 

       MouseToScreen(&Video,x,y,&xpos,&ypos);

       RestoreMouseRect(&Video,xppos,yppos);  //Restore previous screen rectangle.

       DrawMouse(&Video,xpos,ypos);  //Draw mouse in the new location.

       xppos = xpos;

       yppos = ypos;

}

 

上述代码中,首先把鼠标位置,转换为屏幕位置(因为屏幕分辨率是可以变化的,而鼠标的坐标却一直固定),然后调用RestoreMouseRect函数,恢复被鼠标覆盖的矩形。最后再调用DrawMouse函数,在新的位置上画出鼠标指针。

 

posted on 2009-04-11 10:41  三少爷的剑123  阅读(133)  评论(0编辑  收藏  举报

导航