|
|
| |
| 智能手机Smartphone开发从零起步(五) |
| |
实践开发
1、开发实例准备
鉴于本篇的定位,本文的例子是一个很简单的程序,运行后,程序主窗口会显示一行欢迎信息;程序底部会有两个菜单,一个是"关于",一个是"选项","选项"是一个弹出式菜单,上面有两个菜单项"关于"和"退出"。
执行"关于"菜单会显示一个标准的信息对话框;执行"退出"菜单,会首先显示一个消息提示窗口,提醒你是否确认要退出,你可以选择"确定"退出本程序,也可以选择"取消"返回到程序的主界面。
下面是软件执行时的情况:
2、第一步:建立通用框架
因为Smartphone不支持MFC,因此,我们需要建立一个基于Windows CE API的编程框架,有过桌面开发或者Pocket PC开发经验的人会很清楚这个过程,包括注册窗口类、实例初始化、消息循环及窗口过程回调处理等,在Smartphone上也是一样的。
1) 打开eMbedded C++ 4.0 ,File -> New ,建立一个Smartphone 2003 工程:
注意,选择了WCE ARMV4 和WCE emulator 使我们可以编译在模拟器和真实设备运行的程序。
点击OK按钮进入下一步。
2) 选择建立一个空的工程。
确认后此工程被建立。
这里之所以不使用系统的标准框架是因为标准框架采用的是老式的消息处理方案,使用了很多的switch 语句来处理消息,不够灵活,也不方便程序的扩展,因此,这里从一个空的工程开始,仿照MFC消息映射的做法来构建一个结构良好,代码优美的框架,作为我们开发smartphone程序的基础。
3、选择File->New新建一个C++源文件First.cpp和C++头文件First.h,并同时加入First工程。
4、编写文件First.h和First.cpp如下,文件很短,关键的地方已经使用红色标注出来了,如果你有兴趣,可手工敲入下面的代码,以加深你对这个基本过程的了解。
//=============================================================== // first.h 文件
// 避免头文件的重复包含 #ifndef _CHUYUNFENG_FIRST_H_ #define _CHUYUNFENG_FIRST_H_
// 计算需要处理的消息数目 #define MSG_NUM(x) (sizeof(x) / sizeof(x[0]))
// 整个程序的消息映射结构 typedef struct tagMSG_MAP_MAIN { UINT nMsg; LRESULT (*pMsgProcess)(HWND, UINT, WPARAM, LPARAM);
}MSG_MAP_MAIN_S;
// 命令消息(WM_COMMAND)的消息映射结构,因为两者处理函数 // 的参数不同,调用场合也不同,因此这里需要单独建立,类似的有 // WM_NOTOFY消息,本程序中不涉及 typedef struct tagMSG_MAP_CMD { UINT nMsg; LRESULT (*pMsgProcess)(HWND, WORD, HWND, WORD);
}MSG_MAP_CMD_S;
// 声明程序中用到的全局变量 extern const TCHAR g_szAppName[]; extern HINSTANCE g_hInstance; extern HWND g_hMainWnd; extern const MSG_MAP_MAIN_S g_mainMsg[]; extern const MSG_MAP_CMD_S g_cmdMsg[];
// 窗口处理函数原型 LRESULT CALLBACK mainWndProc(HWND, UINT, WPARAM, LPARAM);
// 需要处理的主框架消息定义函数 LRESULT onCreate(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam); LRESULT onPaint(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam); LRESULT onCommand(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam); LRESULT onDestroy(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam);
// 需要处理的菜单命令消息定义函数 LRESULT onAbout(HWND hWnd, WORD idItem, HWND hwndCtl,WORD wNotifyCode); LRESULT onExit(HWND hWnd, WORD idItem, HWND hwndCtl,WORD wNotifyCode);
#endif //_CHUYUNFENG_FIRST_H_
//================================================================= // First.cpp 文件
#include <windows.h> #include <windowsx.h> #include <aygshell.h> #include "resource.h"
#include "First.h"
// 定义程序中用到的全局变量 const TCHAR g_szAppName[] = _T("First"); HINSTANCE g_hInstance; HWND g_hMainWnd;
// 程序中需要处理的消息映射,如果要增加,在此处增加一 // 对{msgID,onMsgProcFun},然后写对应的消息处理函数即可。 const MSG_MAP_MAIN_S g_mainMsg[] = { {WM_PAINT, onPaint}, {WM_COMMAND, onCommand}, {WM_CREATE, onCreate}, {WM_DESTROY, onDestroy} };
//此处放置需要处理的命令消息 const MSG_MAP_CMD_S g_cmdMsg[] = { {IDM_ABOUT, onAbout}, {IDM_EXIT,onExit} };
//================================================================= // WinMain,入口函数,由操作系统调用 //================================================================= int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) { WNDCLASS wc; MSG msg;
// 注册窗口类 wc.style = 0; // 窗口样式 wc.lpfnWndProc = mainWndProc; // 回调函数 wc.cbClsExtra = 0; // 扩展的类数据 wc.cbWndExtra = 0; // 扩展的窗口数据 wc.hInstance = hInstance; //实例句柄 wc.hIcon = NULL, // 图标 wc.hCursor = NULL; // 鼠标 wc.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH); wc.lpszMenuName = NULL; //菜单 wc.lpszClassName = g_szAppName; //窗口类的名字
if ( 0 == RegisterClass (&wc)) return 0; //注册窗口类失败
// 建立并显示程序主窗口 g_hInstance = hInstance; g_hMainWnd = CreateWindow (g_szAppName, // 窗口类 _T("第一个演示程序"), //窗口标题 WS_VISIBLE, //样式 CW_USEDEFAULT, // x坐标 CW_USEDEFAULT, // y 坐标 CW_USEDEFAULT, // 初始宽度 CW_USEDEFAULT, // 初始高度 NULL, // 父窗口 NULL, //菜单,必须为NULL,WINCE窗口不支持菜单。 hInstance, // 实例 NULL); //建立参数的指针,用于WM_CRATE消息期间。
if ( !IsWindow (g_hMainWnd)) //建立窗口失败 return 0;
ShowWindow (g_hMainWnd, nCmdShow); UpdateWindow (g_hMainWnd);
// 消息循环 while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg); DispatchMessage (&msg); }
// WinMain函数成功则返回退出消息的wParam return msg.wParam; }
//====================================================================== // MainWndProc,窗口过程,回调函数,由操作系统调用 //====================================================================== LRESULT CALLBACK mainWndProc (HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam) { // 处理我们需要处理的消息 int i; for (i = 0; i < MSG_NUM(g_mainMsg); i++) { if (wMsg == g_mainMsg[i].nMsg) return (*g_mainMsg[i].pMsgProcess)(hWnd, wMsg, wParam, lParam); }
// 有编写对应的函数则调用默认的 return DefWindowProc (hWnd, wMsg, wParam, lParam); }
//================================================================= // onCreate,WM_CREATE 消息的处理函数 //================================================================= LRESULT onCreate(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam) { SHMENUBARINFO mbi;
// 初始化menubar结构 memset(&mbi, 0, sizeof(SHMENUBARINFO)); mbi.cbSize = sizeof(SHMENUBARINFO); // 必须填充 mbi.hwndParent = hWnd; mbi.nToolBarId = IDR_MAIN_MENUBAR; mbi.hInstRes = g_hInstance;
// 建立menubar控制 if (!SHCreateMenuBar(&mbi)) { MessageBox (hWnd, _T("建立menubar失败"), g_szAppName, MB_OK); DestroyWindow(hWnd); }
// return 0; }
//================================================================= // onPaint,WM_PAINT 消息的处理函数 //================================================================= LRESULT onPaint(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HDC hdc;
RECT rtClient; GetClientRect (hWnd, &rtClient);
// 开始绘图 hdc = BeginPaint (hWnd, &ps);
// 在屏幕中间写一句话 DrawText (hdc, _T("Smartphone第一个程序^_^"), -1, &rtClient, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
// 结束绘图 EndPaint (hWnd, &ps);
return 0; }
//================================================================= // onCommand,WM_COMMAND 消息的处理函数 //================================================================= LRESULT onCommand(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam) { //处理我们需要处理的命令消息 WORD wID, wNotifyCode; HWND hwndCtl; int i;
// 解析出参数 wID = (WORD) LOWORD (wParam); wNotifyCode = (WORD) HIWORD (wParam); hwndCtl = (HWND) lParam;
// 寻找消息映射结构,调用对应的消息处理函数 for (i = 0; i < MSG_NUM(g_cmdMsg); i++) { if (wID == g_cmdMsg[i].nMsg) return (*g_cmdMsg[i].pMsgProcess)( hWnd, wID, hwndCtl,wNotifyCode); } return 0; }
//================================================================= // onDestroy,WM_DESTROY 消息的处理函数 //================================================================= LRESULT onDestroy (HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam) { DestroyWindow(hWnd); return 0; }
//================================================================= // onAbout,菜单消息IDM_ABOUT处理函数 //================================================================= LRESULT onAbout(HWND hWnd, WORD idItem, HWND hwndCtl,WORD wNotifyCode) { TCHAR szAboutMsg[] = _T("\n\n\n\t\tFirst\n\tfor smartphone 2003"); MessageBox(hWnd,szAboutMsg,_T("关于First"),MB_OK); return 0; }
//================================================================= // onExit,菜单消息IDM_Exit处理函数 //================================================================= LRESULT onExit(HWND hWnd, WORD idItem, HWND hwndCtl,WORD wNotifyCode) { if ( IDOK == MessageBox(hWnd, _T("真的要退出这个程序?"), _T("退出确认"),MB_OKCANCEL | MB_ICONASTERISK) ) { PostQuitMessage(0); }
return 0; } | 关键代码分析:
代码中最关键的地方就是使用消息映射的办法来处理消息,这主要体现在定义消息映射结构和在窗口处理函数以及命令消息处理函数中进行消息分发上面,实现可以参看代码中的红色部分。
5) 在框架上的开发。
我们构建这个基本框架,是想使用这个框架进行后续开发的,上述代码中的绿色部分标示出了增加WM_PAINT消息处理的整个过程:
1、 在.h文件中声明消息处理函数;
2、 在.c文件的消息映射结构中增加一个消息映射对;
3、 然后,在.c文件中实现此函数的功能即可。
3、第二步:建立菜单
现在,我们来建立左右软键对应的菜单。
1) 确认使用中文资源
因为要使用资源,因此,首先确认我们项目所使用的是中文资源:选择菜单项 Project ->Settings…,设置资源为中文:
2) 增加resource script文件并修改Evc的一个bugs
菜单File -> new ->增加一个resource script文件,名字为first.rc。
当你在IDE中打开这个RC文件时,会发现一个错误,这是eMbedded C++处理smartphone上的一个bugs,微软对此的修正方案是,提供了一个newRes.h的文件,你将First.rc中的#include "afxres.h"修改为 #include "newRes.h"即可,newRes.h文件你可以自行在程序目录下建立,下面是newRes.h文件内容:
#ifndef __NEWRES_H__ #define __NEWRES_H__
#if !defined(UNDER_CE) #define UNDER_CE _WIN32_WCE #endif
#if defined(_WIN32_WCE) #if !defined(WCEOLE_ENABLE_DIALOGEX) #define DIALOGEX DIALOG DISCARDABLE #endif #include <commctrl.h> #define SHMENUBAR RCDATA #if defined(WIN32_PLATFORM_WFSP) && (_WIN32_WCE >= 300) #include <aygshell.h> #define AFXCE_IDR_SCRATCH_SHMENU 28700 #else #define I_IMAGENONE (-2) #define NOMENU 0xFFFF #define IDS_SHNEW 1
#define IDM_SHAREDNEW 10 #define IDM_SHAREDNEWDEFAULT 11 #endif // _WIN32_WCE_PSPC #define AFXCE_IDD_SAVEMODIFIEDDLG 28701 #endif // _WIN32_WCE
#ifdef RC_INVOKED #ifndef _INC_WINDOWS #define _INC_WINDOWS #include "winuser.h" // extract from windows header #include "winver.h" #endif #endif
#ifdef IDC_STATIC #undef IDC_STATIC #endif #define IDC_STATIC (-1)
#endif //__NEWRES_H__ | 3、 增加menubar资源:
| 类型 |
ID |
Caption |
| Menubar |
IDR_MAIN_MENUBAR |
|
| Left menu |
IDM_ABOUT |
关于 |
| Right menu |
IDM_OPTION |
选项 |
| Right menu subitem 1 |
IDM_ABOUT |
关于(和左建菜单是同一个ID) |
| Right menu subitem 2 |
IDM_EXIT |
退出 | 这是first.rc的内容,大家可以看到,与我们桌面windows下的资源脚本文件相差无几。
[1] [2] 下一页 |
| |
|
|
[]
[返回上一页]
[打 印]
[收 藏] |
|
| ∷相关文章评论∷ (评论内容只代表网友观点,与本站立场无关!) [更多评论...] |
|
|