WINCE应用的UI实现方案 —— 中篇:GWES方案上几技术难点的解决

简介:

这里谈论的所谓技术难点,其实根本不值一提。只不过微软定了一套游戏规则,我们目前不清楚这套游戏规则,花时间去摸索而已。

1、BUTTON的动画效果

我们用了GWES里提供的BUTTON类,在WINCE PRODUCT DOCUMENT里的位置是
ms-help://MS.WindowsCE.500/wceshellui5/html/wce50grfButtonReference.htm
里面并没有给出太多的说明,在Button Messages里提到有WM_CTLCOLORBTN消息, 但简单试用后发现和预期效果不符。我乱翻乱点时注意到了eVC在画图时,对BUTTON点右键出的菜单里,打开Properties,里面的Styles页有个复选框"Owner draw", 我就抓住这根稻草,GOOGLE一把,方法就出来了。

当Owner draw属性被勾选时,轮到该BUTTON绘图时,程序就不会跑DefDlgProc去画个灰色突出的效果并把按钮名字写上去,而是给BUTTON的父窗口,也就是DIALOG的PROC发个消息WM_DRAWITEM,并且所带的lParam中有我们需要的所有东西。来个强制转换
LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT)lParam;
然后根据 lpDIS->itemAction 和 lpDIS->itemState 判断BUTTON当前状态,以决定加载哪幅图片

DRAWITEMSTRUCT的详细说明请参考 ms-help://MS.WindowsCE.500/wceshellui5/html/wce50lrfdrawitemstruct.htm

我简单试了了一下,
(1) 初始化时
 itemAction == 1;  // ODA_DRAWENTIRE
 itemState == 16;  // ODS_FOCUS
(2) BUTTON被按下时 
 itemAction == 2;  // ODA_SELECT
 itemState == 17;  // ODS_FOCUS | ODS_SELECTED
(3) BUTTON被点击后松开时
 itemAction == 2;  // ODA_SELECT
 itemState == 16;  // ODS_FOCUS

ODA和ODS宏定义数值
 /*** from Winuser.h ***/
 #define ODT_MENU        1
 #define ODT_LISTBOX     2
 #define ODT_COMBOBOX    3
 #define ODT_BUTTON      4
 //action
 #define ODA_DRAWENTIRE  0x0001
 #define ODA_SELECT      0x0002
 #define ODA_FOCUS       0x0004
 //state
 #define ODS_SELECTED    0x0001
 #define ODS_GRAYED      0x0002
 #define ODS_DISABLED    0x0004
 #define ODS_CHECKED     0x0008
 #define ODS_FOCUS       0x0010

在WM_DRAWITEM中有两点要特别注意
(1) 不能在里面用InvalidateRect(lpDIS->hwndItem, lpDIS->rcItem, NULL),这会立即再发一个WM_DRAWITEM消息过来,接着再调InvalidateRect, 进入死循环直至把设备上的内存耗光,导致死机
(2) 对itemAction和itemState作判断时,必须把两者同时都判断了才能确定CLICK状态,单独判断action或单独判断state是不够的,会导致重绘作用在不希望发生的情况下。并且不能简单地作itemAction & ODA_SELECT这样的位与判断,还必须有排他性,我干脆就用==号了。

参考代码如下


 1 BOOL CALLBACK DialogProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
 2 {
 3      switch(uMsg)
 4     {
 5          case WM_DRAWITEM:
 6         {
 7             LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT)lParam;
 8 
 9              if(lpDIS->CtlID == IDC_BTN_1)
10             {
11 
12                  if( (lpDIS->itemAction & ODA_DRAWENTIRE)    // 这是初始化时的情况
13                      ||    ( (lpDIS->itemAction == ODA_SELECT) && (lpDIS->itemState == ODS_FOCUS) ) )  // 这是按下后放开时的情况
14                  {
15                      // 画上未被按下时的图片
16                  }
17                  else  if( (lpDIS->itemAction & ODA_SELECT) && (lpDIS->itemState == (ODS_FOCUS | ODS_SELECTED) ) )  // 被按下时的情况
18                  {
19                      // 画上被按下时的图片
20                      MessageBeep(MB_OK);  // 顺便响一声,比较有手感
21                  }
22             }
23              return TRUE;
24         }
25          default:
26              // STUB
27               break;
28     }
29     
30      return FALSE;
31 }


2、DLU和PIXEL的单位转换

本来以为做完BUTTON效果后就OVER了,结果今天傍晚时候遇到一个很恼火的问题。在VC / eVC / VS中画的对话框、按钮等控件时,在IDE右下角显示的 XX * XX单位是DLU (Dialog Unit), 这是根据你设置的对话框字体大小而改变的。这种做法无可厚非。如果把字体改大了,那么DIALOG和BUTTON自然也被“撑”大了,比较灵活。但是我往上叠加的图片是按像素(PIXEL)来算的。最后实现出来,有两个方法。按照国际惯例,当然是先讲笨的方法,MSDN上的作风也是如此。

(1)方法一:我查了下DLU和PIXEL之间的换算关系,有个讲得比较全的网页是 http://support.microsoft.com/default.aspx?scid=kb;en-us;145994 (How to caculate dialog box units based on the current font in Visual C++) 按照文中的Method Two简单测试了一下

 1 BOOL CALLBACK DialogProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
 2 {
 3      switch(uMsg)
 4     {
 5          case WM_INITDIALOG:
 6         {
 7             RECT rc={0,0,4,8};
 8 
 9             MapDialogRect(hDlg, &rc );
10             printf("baseUnitX = %ld\n", rc.right);
11             printf("baseUnitY = %ld\n", rc.bottom);
12 
13              // DLU_Weight = pixel_weight * 4 / baseunitX;
14               // DLU_Height = pixel_height * 8 / baseunitY;
15 
16              return TRUE;
17         }
18     }
19 
20      return FALSE;
21 }


对于我DIALOG中设置的Courier New 10pt字体,
第一步:从代码中得到baseUnitX = 7, baseUnitY = 16,
第二步:套用公式
 weight_DLU = weight_pixel * 4 / baseUnitX
 height_DLU = height_pixel * 8 / baseUnitY
 比如我想建立一个320*240 PIXEL的对话框,那么
 weight_DLU = 320 * 4 / 7 = 182.86, 取整为183
 height_DLU = 240 * 8 / 16 = 120
第三步:到VC里去拖动对话框的边界,画出183*120的对话框,那么代码运行起来后,通过GetClientRect查一下,的确是得到320*240 pixel的对话框了。

但是这种方法有一个致命的缺点。比如我要画一个60*70的按钮,按照上面的baseUnitX和baseUnitY折算后应该为34.28 * 35,但是我画34*35 DLU时,运行得到59*70 PIXEL窗口;画35*35 DLU时,运行得到61*70 PIXEL窗口,无法恰到好处,这导致了往上叠加60*70 pixel的图片时,按钮边缘会出现不连续的黑点。所以这段文字只能当作DLU和PIXEL的换算关系来玩了,没有任何实际应用价值。

(2) 方法二:正确的方法
 其实也很简单。晚饭后突然想到的,用SetWindowPos强制设置window的长宽和左上角坐标。我在WM_DRAWITEM消息的处理中简单试了一下:
SetWindowPos(lpDIS->hwndItem, NULL, 10, 10, 60, 70, SWP_NOZORDER);
设置前是59*70的按钮,设置后就是60*70了,并且叠加图片没有任何问题。OK,整个基于GWES的UI方案至此成型了。后面貌似没有什么大的技术障碍了。

至此,我没有发现GWES方案上还有什么路障了,可以拍板使用这套方案了,和只用GDI写UI相比,软件研发的工作量大概降低了30%左右。当然事情还没有就这样结束,这套方案对我这项目组的意义是很深远的。请看下篇:代码中的一小步,项目进度管理上的一大步


本文转自Walzer博客园博客,原文链接:http://www.cnblogs.com/walzer/archive/2007/04/08/704996.html,如需转载请自行联系原作者


相关文章
|
前端开发 安全 开发工具
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
898 90
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
9月前
|
定位技术 容器
48.[HarmonyOS NEXT RelativeContainer案例五] 精确表单布局:辅助线定位技术打造专业级UI
在HarmonyOS NEXT的UI开发中,表单是常见且重要的界面元素。创建对齐精确、布局合理的表单需要精细的定位控制。RelativeContainer提供的辅助线(Guideline)功能,为表单布局提供了强大的支持。本教程将详细讲解如何使用RelativeContainer的辅助线功能实现精确的表单布局,帮助你掌握这一专业级UI技术。
249 7
|
人工智能 自然语言处理 API
用自然语言控制电脑,字节跳动开源 UI-TARS 的桌面版应用!内附详细的安装和配置教程
UI-TARS Desktop 是一款基于视觉语言模型的 GUI 代理应用,支持通过自然语言控制电脑操作,提供跨平台支持、实时反馈和精准的鼠标键盘控制。
5178 17
用自然语言控制电脑,字节跳动开源 UI-TARS 的桌面版应用!内附详细的安装和配置教程
|
UED
「Mac畅玩鸿蒙与硬件52」UI互动应用篇29 - 模拟火车票查询系统
本篇教程将实现一个模拟火车票查询系统,通过输入条件筛选车次信息,并展示动态筛选结果,学习事件处理、状态管理和界面展示的综合开发技巧。
395 13
「Mac畅玩鸿蒙与硬件52」UI互动应用篇29 - 模拟火车票查询系统
「Mac畅玩鸿蒙与硬件53」UI互动应用篇30 - 打卡提醒小应用
本篇教程将实现一个打卡提醒小应用,通过用户输入时间进行提醒设置,并展示实时提醒状态,实现提醒设置和取消等功能。
364 10
「Mac畅玩鸿蒙与硬件53」UI互动应用篇30 - 打卡提醒小应用
|
10月前
|
开发框架 前端开发 JavaScript
【HarmonyOS Next之旅】基于ArkTS开发(二) -> UI开发一
本文介绍了方舟开发框架(ArkUI)及其两种开发范式:基于ArkTS的声明式开发范式和类Web开发范式。ArkUI是用于构建HarmonyOS应用界面的UI框架,提供极简UI语法和基础设施。声明式开发范式使用ArkTS语言,以组件、动画和状态管理为核心,适合复杂团队协作;类Web开发范式采用HML、CSS、JavaScript三段式开发,适用于简单界面应用,贴近Web开发者习惯。文中还概述了两者的架构和基础能力,帮助开发者选择合适的范式进行高效开发。
352 15
|
10月前
|
编解码 前端开发 Java
【HarmonyOS Next之旅】基于ArkTS开发(二) -> UI开发三
本文介绍了基于声明式UI范式的图形绘制与动画效果实现方法,涵盖绘制图形、添加动画效果及常见组件说明三部分内容。在绘制图形部分,详细讲解了如何通过Circle组件为食物成分表添加圆形标签,以及使用Path组件结合SVG命令绘制自定义图形(如应用Logo)。动画效果部分则展示了如何利用animateTo实现闪屏动画,包括渐出、放大效果,并设置页面跳转;同时介绍了页面间共享元素转场动画的实现方式。最后,文章列举了声明式开发范式中的各类组件及其功能,帮助开发者快速上手构建复杂交互页面。
372 11
|
6月前
|
存储 开发者 容器
鸿蒙 HarmonyOS NEXT星河版APP应用开发-ArkTS面向对象及组件化UI开发使用实例
本文介绍了ArkTS语言中的Class类、泛型、接口、模块化、自定义组件及状态管理等核心概念,并结合代码示例讲解了对象属性、构造方法、继承、静态成员、访问修饰符等内容,同时涵盖了路由管理、生命周期和Stage模型等应用开发关键知识点。
504 1
鸿蒙 HarmonyOS NEXT星河版APP应用开发-ArkTS面向对象及组件化UI开发使用实例
|
9月前
|
JavaScript 前端开发 UED
【HarmonyOS Next之旅】基于ArkTS开发(二) -> UI开发四
本文介绍了Web组件开发与性能优化的相关内容。在Web组件开发部分,涵盖创建组件、设置样式与属性、添加事件和方法以及场景示例,如动态播放视频。性能提升方面,推荐使用数据懒加载、条件渲染替代显隐控制、Column/Row替代Flex、设置List组件宽高及调整cachedCount减少滑动白块等方法,以优化应用性能与用户体验。
327 56
|
9月前
|
编解码 UED 开发者
【HarmonyOS Next之旅】基于ArkTS开发(二) -> UI开发之常见布局
本文主要介绍了自适应布局与响应式布局的相关内容。自适应布局部分涵盖线性布局、层叠布局、弹性布局和网格布局,详细说明了各布局的特性及使用方法,例如线性布局中的排列、拉伸与缩放,弹性布局的方向、换行与对齐方式等。响应式布局则重点讲解了栅格系统和媒体查询,阐述如何通过栅格组件和媒体查询条件实现不同设备上的适配效果。这些技术帮助开发者灵活应对多尺寸屏幕的设计需求,提升用户体验。
476 55

热门文章

最新文章