wince6.0 屏幕旋转

转载至http://blog.csdn.net/shen8686/article/details/5989977

最近做了一个wince下屏幕旋转的测试. 我实现的效果是一个基于wince的应用程序, 显示区域有个button,  每按一次这个button,屏幕会旋转90度. 这个东东我调了整整三天, 中间遇到很多问题, 最后总算成功了,最关键的是,我对wince的显示驱动有了更深的认识. 拿来分享一下.

要实现上述功能, 主要有两个操作, 一个是对操作系统本身做一些支持屏幕旋转的驱动修改. 二是上层应用程序本身做的一些图形模式的改变以及相关消息的处理.

第一步:先来看看显示驱动是否支持屏幕旋转. 怎么来看显示驱动是否支持屏幕旋转呢? 显示驱动的类要从GPERotate类继承. 并实现其中的一些方法. 我应该到我的当前系统的BSP下看看显示驱动下的源程序. 我的板子是优龙的FS2410, 显示驱动就在smdk2410BSP包下. 打开DRIVERS目录. 找到DISPLAY文件夹, 这个文件夹下面的所有东西都是和显示驱动有关的. 在名为s3c2410disp.h的文件里我找到了下面几行代码.

#ifdef ROTATE

class S3C2410DISP : public GPERotate

#else

class S3C2410DISP : public GPE

#endif //ROTATION

很明显S3C2410DISP就是上面提到的显示驱动的主要实现类, 系统根据有没有定义ROTATE来决定该类从哪个基类继承. 上面两个基类是在gep.h(在public/common/oak/inc下可以找到)定义的. 另外在这个文件里可以找到下面一条语句:

typedef GPE     GPERotate;

噢, 原来这两个类其实是一样的. 只是实现类的方法时根据ROTATE这个宏定义是否定义去做不同的处理. 事实上,wince下的display驱动就是基于GPE类来实现的, GPE是graphics primitive engine的缩写, 实现了一些基本的绘图rr 操作, 但它里面大部分还是纯虚函数(所以这个类也是纯虚类喽,你必须继承它),继承类需要去实现大部分的操作. GPE的实现代码微软是没有公开的.  从wince驱动程序结构上分析,GPE 这部分就相当于是MDD,而S3C2410DISP就是PDD,对于我们开发者而言,只需要实现这个基于特定硬件平台的PDD部分就行了.

在.h和.cpp时到处找了一下,发现并没有ROTATE这个宏定义, 所以系统默认并不支持屏幕旋转, 于是我在S3C2410DISP.h里加了一个宏定义

#ifndef ROTATE

#define  ROTATE

#endif

S3C2410DISP.cpp文件就不用去修改了, 因为加上了宏定义后,实现方法里会自动作相应的处理.

第二步:打开在同一级目录的source文件, 可以找到下面几行代码:

TARGETLIBS=                                             /

    $(_COMMONSDKROOT)/lib/$(_CPUINDPATH)/coredll.lib    /

!IFDEF ROTATE

    $(_COMMONOAKROOT)/lib/$(_CPUINDPATH)/emulrotate.lib       /

    $(_COMMONOAKROOT)/lib/$(_CPUINDPATH)/gperotate.lib        /

!ELSE

    $(_COMMONOAKROOT)/lib/$(_CPUINDPATH)/emul.lib       /

    $(_COMMONOAKROOT)/lib/$(_CPUINDPATH)/gpe.lib        /

!ENDIF

 

SOURCELIBS= /

!IF "$(CLEARTYPE)" == "1"

!IFDEF ROTATE

    $(_COMMONOAKROOT)/lib/$(_CPUINDPATH)/rctblt.lib /

!ELSE

    $(_COMMONOAKROOT)/lib/$(_CPUINDPATH)/ctblt.lib /

!ENDIF

!ENDIF

很容易看明白,有没有定义ROTATE,链接的库文件是不一样的(上面说GPE源代码microsoft没有公开,就是隐藏在这些库文件里),所以这里也要改, 在source作宏定义与C稍不同, 只要在上面那几行代码上面加上

ROTATE = 1

到这里,显示驱动就已经可以支持屏幕旋转了.

第三步: 下面就可以去写应用程序测试屏幕旋转了. 但是抱着”学术钻研”的精神,还是想去.cpp里分析一下三星的工程师到底是怎么实现屏幕旋转的吧(只讲几个重要的实现方法)

和屏幕旋转有关的主要函数有下面几个

void   S3C2410DISP::CursorOn (void)

void   S3C2410DISP::CursorOff (void)

上面两个显然是做光标的使能和禁用. 当屏幕支持旋转时,这两个函数要做特殊的处理. 因为屏幕旋转时,鼠标也要旋转.

void S3C2410DISP::SetRotateParms()

SCODE  S3C2410DISP::BltPrepare(GPEBltParms *blitParameters)

查到的资料是这样说的:

Called before the blit operation is performed. It allows the driver to setup the blit hardware for performing the operation, if it is supported. It must return the actual function to be called to perform the blit operation, which can be the default blit function provided in the GPE class

这个函数主要设置屏幕在不同的角度时,width和height的大小. 容易想到,0和180度是一样的, 90和270度的设置参数也是一样的.

下面要说一下Surface这个概念.

m_pPrimarySurface = new GPESurfRotate(m_nScreenWidthSave, m_nScreenHeightSave, (void*)(m_VirtualFrameBuffer), m_cbScanLineLength, m_ModeInfo.format);

这行分配了一个GPESurf类的指针, GPESurf类从名字也可以看出是一个图像存储和显示的类, 它主要是对二维图像的一个存储显示管理.可以把GPE看作是一个显示驱动的管理类, 而GPESurf则是一个显存. GPESuf类最重要的一个成员变量就是ADDRESS         m_pVirtAddr;这个变量跟S3C2410DISP类的m_VirtualFrameBuffer变量相关联,指向所存储的二维图像. surface, 它可以说是bitmap另一种表示形式,这种表示形式可以在wince驱动里直接访问(bitmap就不行).

第四步:该说到上层应用了

在evc下建一个基于wince application的应用程序, 基于单文档. 我要实现的效果是,在客户区有一个button, 每当我按一下这个button, 屏幕就旋转90度

1 创建button的代码如下,在WM_CREATE加入下面的语句

hwndRotateButton = CreateWindow(TEXT("button"), TEXT("Rotate me"),

              WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,30,30,100,75,hWnd,

           (HMENU)1, ((LPCREATESTRUCT)lParam)->hInstance,NULL);

           break;

注意这个(HMENU)1,这个就是button的ID,一会在WM_COMMAND里要做事件判断.

2 在WM_COMMAND的switch里加入下面的代码:

    case 1://按钮"rotate me"事件

                  memset(&devmode, 0x00, sizeof(devmode));

                  devmode.dmSize = sizeof(devmode);

                  //devmode.dmFields = DM_DISPLAYQUERYORIENTATION;

                  devmode.dmFields = DM_DISPLAYORIENTATION;

                 

                  if(DISP_CHANGE_SUCCESSFUL == ChangeDisplaySettingsEx(NULL, &devmode, NULL, CDS_TEST, NULL))

                  {

                     //MessageBox(TEXT("change display ok!"), NULL, MB_OK);

                     switch(devmode.dmDisplayOrientation)

                     {

                     case DMDO_0:

                         newAngle = DMDO_90;

                         break;

                     case DMDO_90:

                         newAngle = DMDO_180;

                         break;

                     case DMDO_180:

                         newAngle = DMDO_270;

                         break;

                     case DMDO_270:

                         newAngle = DMDO_0;

                         break;

                     default:

                         newAngle = DMDO_0;

                         break;

                     }

                    

                     memset(&devmode, 0, sizeof(devmode));

                     devmode.dmSize = sizeof (devmode);

                     devmode.dmFields = DM_DISPLAYORIENTATION;

                     devmode.dmDisplayOrientation = newAngle;

 

                     if(DISP_CHANGE_SUCCESSFUL != ChangeDisplaySettingsEx(NULL, &devmode, NULL, CDS_RESET, NULL))

                     {

                         MessageBox(hWnd, TEXT("change to new setting error"), NULL, MB_OK);

                         return 1;

                     }

                     break;

                  }

                  else//更改图形模式失败.

                  {

                     MessageBox(hWnd, TEXT("failed to change graphic settings!"), NULL, MB_OK);

                     return 1;

                  }

                  break;

注意到case 1了吧,就是button的ID. 这里做屏幕旋转的主要工作, 可以看到ChangeDisplaySettingsEx函数起到了最重要的作用, 事实上,要在应用程序改变屏幕方向,只能通过该函数.它的详细用法,可以去查MSDN. 我只简单说几个要注意的地方.

在OnRotate事件中, 有下面一条语句

devmode.dmFields = DM_DISPLAYORIENTATION

dmFields被这样赋值时,调用ChangeDisplaySettingsEx,如果传CDS_TEST,就可以获取屏幕当前的角度.

我们也可以在获取当前屏幕之前,确认系统是否支持屏幕旋转.通过下面两条语句就可以了:

devmode.dmFields = DM_DISPLAYQUERYORIENTATION;                    

ChangeDisplaySettingsEx(NULL, &devmode, NULL, CDS_TEST, NULL);

有了上面两行语句,通过查看devmode. dmDisplayOrientation域的值就可以知道当前

当前系统是否支持屏幕旋转了. 如果这个域的值为0,则不支持屏幕旋转,为7,则支持90,180,270三个角度的旋转.因为有如下的定义:

#define DMDO_0      0

#define DMDO_90     1

#define DMDO_180    2

#define DMDO_270    4

3 当设置新的角度成功后,系统会向所有的应用程序发送WM_SETTINGCHANGE消息. 新的图形模式信息会通过devmode返回,我们的应用程序应该拦截该消息去做一些窗体的调整. 另外,窗体大小的改变肯定也会触发WM_SIZE消息,所以我们可以加入这两个消息

case WM_SIZE:

           //重新确定子窗口的布局(比如按钮,因为子窗口收不到WM_SIZE消息)

           //另外菜单栏的显示也要做相应的调整.

           break;

       case WM_SETTINGCHANGE: //刷新显示器.主要做的事是调整全屏窗口.

           if (wParam == SETTINGCHANGE_RESET)//屏幕方向发生改变.

           {

              int nScreenX, nScreenY;

              nScreenX = GetSystemMetrics(SM_CXSCREEN);//获取X,Y方向上的尺寸.

              nScreenY = GetSystemMetrics(SM_CYSCREEN);

              MoveWindow(hWnd, 0, 0, nScreenX, nScreenY, TRUE);//调整全屏窗口,也就是程序默认建的一个单文档窗体.

           }

           break;

在两个消息里,我没有做太多的事,只是用注释说明了一下大概要做什么, 因为我已经实现屏幕旋转,这两个消息主要是处理一些窗体的调整和美化,做一些用户界面体验的工作. 真正做一个产品时,这里面有大把工作要做.

写完收工. 希望对大家有所帮助.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值