构建可移植 BREW™ 应用程序的方法
2003年9月12日 作者:高通 移动锋行
遵循以下原则,可使 BREW 应用程序具有可移植性:
1. 使用资源文件 - 将资源与代码分离
BREW 应用程序可设计为在多种不同设备上并以多种不同语言执行。 您无需为每台设备和每种语言单独创建应用程序,而只需使用资源编辑器创建多个资源文件(.bar 文件)- 每种设备语言组合一个。 以这种方式将资源与代码分离将使您的 BREW 应用程序可以跨设备和语言进行移植。
您应该使用资源编辑器添加应用程序使用的所有字符串、图像和对话框资源。 然后,将每个资源与一个名称相关联,应用程序代码中将使用该名称。 有关如何生成资源 (.bar) 文件的详细信息,请参阅 BREW SDK™ 随附的《资源编辑器指南》。
2. 对每个目标设备使用不同的 MIF 文件
MIF 文件包含用于在可执行应用程序的菜单中显示应用程序的字符串和图像。 因此,您应该为每个设备语言组合创建不同的 MIF 文件。
3. 参照屏幕尺寸定位控件 - 不要使用绝对像素值作为屏幕坐标
不同的目标设备具有不同的屏幕尺寸和不同的字体高度、宽度。 以下 BREW API 可用于获得这些特性,在设备上布置文本、图像和控件时将用到这些 API:
• ISHELL_GetDeviceInfo()
ISHELL_GetDeviceInfo 用于确定运行应用程序的设备的屏幕尺寸。
AEEDeviceInfo di;
int cx, cy;
ISHELL_GetDeviceInfo(pIShell, &di);
cx = di.cxScreen; //设备宽度(像素)
cy = di.cyScreen; //设备高度(像素)
• IDISPLAY_GetFontMetrics()
IDISPLAY_GetFontMetrics() 用于查找特定字体的字符高度。
int fontHeight;
fontHeight = IDISPLAY_GetFontMetrics(pme->a.m_pIDisplay,
AEE_FONT_BOLD, NULL,
NULL);
• IDISPLAY_MeasureText()
使用指定字体进行绘制时,可使用 IDISPLAY_MeasureText() 测量给定字符串的像素宽度。
int stringWidth = IDISPLAY_MeasureText(pme->a.m_pIDisplay,
AEE_FONT_NORMAL,
textString);
• IDISPLAY_MeasureTextEx()
如果给定用于显示字符串的最大像素宽度和字体,则可使用 IDISPLAY_MeasureTextEx() 确定可以显示的输入文本字符串的字符数。
pixelWidth = IDISPLAY_MeasureTextEx(pMe->m_pIDisplay,
AEE_FONT_BOLD,
(AECHAR *) textString, // 文本字符串
-1,
di.cxScreen, // 最大宽度
&pnFits); // 可容纳的字符数
// 最大宽度
pixelWidth 包含输入文本字符串的像素宽度。
pnFits 包含设备一行中可以容纳的输入文本字符串的字符数。
• IIMAGE_GetInfo()
IIMAGE_GetInfo() 用于获取图像尺寸。
AEEImageInfo imgInfo;
int cx,cy;
IIMAGE_GetInfo(pIImage, &imgInfo);
cx = imgInfo.cx; //图像宽度
cy = imgInfo.cy; // 图像高度
使用以上 API,您无需对像素值进行硬编码就可以定位屏幕上的元素。
例如:
要绘制跨多行的文本:
// 获取设备信息
ISHELL_GetDeviceInfo(pMe->m_pIShell,&di);
// 获取字体量度信息
charHeight = IDISPLAY_GetFontMetrics (pMe->m_pIDisplay,
AEE_FONT_NORMAL, &pnAscent, &pnDescent);
// 转换为宽字符串 (unicode)
STR_TO_WSTR ((char *)displayStr, wideStr, sizeof (wideStr));
// psz 跟踪字符串缓冲区中开始写入的点
// 以防止在一行中无法容纳字符串时,需要换至
// 下一行。
psz = wideStr;
// 需要计算字符串总长度,以确定是否要
// 换行。
totalCh = STRLEN ((char *)wideStr);
// 如果文本字符串无法在单行中完全显示,则使之
// 多行显示。
while ((totalCh > 0) && (*psz != NULL)) {
// 获取一行中可容纳字符数的信息。
pixelWidth = IDISPLAY_MeasureTextEx(pMe->m_pIDisplay, font,
(AECHAR *) psz, -1, di.cxScreen - 5, &pnFits);
IDISPLAY_DrawText(pMe->m_pIDisplay, AEE_FONT_NORMAL,
psz,
pnFits, 5, dy, 0, 0);
psz += pnFits;// 将指针移到下一个要显示的
// 段
totalCh -= pnFits;// 减少仍需要显示的字符
// 总数
dy += charHeight;// 将下一行置于上一行的 charHeight 像素
// 以下。
IDISPLAY_Update(pMe->m_pIDisplay);
if (totalCh < pnFits) {
pnFits = totalCh; // 如果总数小于 pnFits,
// 则调整 pnFits
}
}
要在屏幕中心显示图像:
// 获取设备坐标
ISHELL_GetDeviceInfo(pMe->a.m_pIShell, &dInfo);
// 从资源文件加载图像
pIImage = ISHELL_LoadResImage(pMe->a.m_pIShell, szResFile,
IDB_BROWSER_ICON);
if (pIImage) {
// 获取图像尺寸
IIMAGE_GetInfo(pIImage, &aii);
// 计算位图坐标 --
// 在屏幕中心显示位图
img_x = (dInfo.cxScreen - aii.cx) / 2;
img_y = (dInfo.cyScreen - aii.cy)/ 2;
// 设置光栅操作
IIMAGE_SetParm(pIImage, IPARM_ROP, AEE_RO_NOT, 0);
// 在指定坐标处绘制非动画位图
IIMAGE_Draw(pIImage,img1_x,img1_y);
// 释放图像接口
IIMAGE_Release (pIImage);
}
4. 使用适当颜色深度的图像
对于不同的目标设备,应使用不同的资源文件。在这些文件中,使用颜色深度适合设备的图像。 如果您从外部网络获得图像,则可以查阅设备的颜色深度(包括屏幕尺寸)并使用这些值获取合适的图像。
AEEDeviceInfo di;
int cx, cy, colorDepth;
ISHELL_GetDeviceInfo(pIShell, &di);
cx = di.cxScreen; //设备宽度(像素)
cy = di.cyScreen; //设备高度(像素)
colorDepth = di.nColorDepth; // 设备的颜色深度
5. 伸展图像
在 BREW SDK 1.1 版中,可以使用 IGRAPHICS_StretchBlt() 将位图伸展到所需宽度和高度。 您可以比较屏幕尺寸(使用 ISHELL_GetDeviceInfo)和图像尺寸 (IIMAGE_GetInfo),然后根据需要将位图伸展到更加适当的大小。
IGRAPHICS_StretchBlt(pIGraphics,
xStart, //图像左上角的 x 和 y
yStart, // 坐标
width, // 所需图像宽度
height, // 所需图像高度
sourceBmp //源位图
rasterCode)
6. 动态查找特定图像或声音类型的处理程序
确定图像/声音类型的处理程序函数的 Class ID,然后
创建该 BREW 类的实例。
// 查找 bmp 图像处理程序的类 ID
if ((cls = ISHELL_GetHandler(pMe->a.m_pIShell, HTYPE_VIEWER,
"image/bmp")) == 0)
break;
// 使用返回的类 ID 创建图像处理程序的实例
ISHELL_CreateInstance(pMe->a.m_pIShell, cls, (void **)(&pIImage));
if(pIImage == NULL)
break;
7. 自定义菜单样式
使用标准菜单样式创建菜单时,菜单可能在不同的目标设备上不一样。 要保持您的菜单有一致的外观,您可以使用 IMENU_SetStyle() 自定义菜单样式(项目的边框类型、项目内 x 方向的填充、项目内 y 方向的填充、项目内绘制图像的光栅操作)。
AEEItemStyle si, ni;
// 选定菜单项的项目样式
si.ft = AEE_FT_TAB_TOP_SEL; // 项目的边框类型
si.xOffset = 8; // 项目内 X 方向的填充(不包括边框大小)
si.yOffset = 8; // 项目内 Y 方向的填充(不包括边框大小)
si.roImage = AEE_RO_COPY; // 项目内绘制图像的光栅
// 项目
// 一般菜单项的项目样式
ni.ft = AEE_FT_TAB_TOP; // 项目的边框类型
ni.xOffset = 8; // 项目内 X 方向的填充(不包括边框大小)
ni.yOffset = 8; // 项目内 Y 方向的填充(不包括边框大小)
ni.roImage = AEE_RO_COPY; // 项目内绘制图像的光栅
// 项目
// 现在设置刚刚创建的项目样式
IMENUCTL_SetStyle(pMe->m_pStdMenu, &ni, &si);