如何使用 eMbedded Visual C++ 4.0 创建用于 Windows CE 4.1 仿真程序 (Windows CE5.0) 的应用程序
适用于:
Microsoft® eMbedded Visual C++® version 4.0
Microsoft® Windows® CE version 4.1
摘要:本文为熟悉 eMbedded Visual C++ 编程环境及创建应用程序并将其下载到 Windows CE 4.1 仿真程序提供了逐步说明。本文共分为五个部分,每一部分都包含读者可以完成的许多练习。完成所有这些步骤大约需要 60 分钟。
从 Microsoft Download Center 下载 Windows CE 5.0 Embedded Development Labs.msi。
本页内容
第一部分:创建用于 Windows CE 4.1 仿真程序的 MFC 应用程序 | |
第二部分:向应用程序中添加鼠标捕获和手写输入绘图 | |
第三部分:修改应用程序以存储和重绘手写输入 | |
第四部分:探索 eMbedded Visual C++ 的调试功能 | |
第五部分:添加代码保存和打开手写输入文档 | |
小结 |
第一部分:创建用于 Windows CE 4.1 仿真程序的 MFC 应用程序
Microsoft® eMbedded Visual C++® 开发系统提供了一个与 Microsoft Visual C++ 6.0 版几乎相同的编程环境。该环境及 Microsoft Windows® CE 的 Microsoft Win32® 应用程序编程接口 (API) 使编写基于 Windows CE 设备的应用程序非常类似于编写 Windows 桌面版应用程序。
在本文的该部分中,将使用 Microsoft 基础类 (MFC) 应用程序向导创建一个应用程序,您可以将该应用程序下载到 Microsoft Windows CE .1 版仿真程序并在其上运行。
在本文中,您可以点击大多数缩略图查看大图像。
在该部分的练习中,您将执行以下步骤:
• | 创建一个新的 Windows CE MFC 项目 |
• | 在平台管理器中配置设置 |
• | 生成和部署第一个仿真程序应用程序 |
要创建新的 Windows CE MFC 项目
1. |
启动eMbedded Visual C++。 eMbedded Visual C++ 的基本用户界面如下图所示。必要时,先花几分钟时间浏览一下这些工具,再进入下一个步骤。 |
2. |
在 New 对话框中,选择 WCE MFC AppWizard (exe) 作为待创建项目。 |
3. |
在 Project name 框中,键入 Scribble |
4. |
在 Location 框中,输入 C:\LABS\EVCBASIC。 |
5. |
对于 Windows CE,您不会像在 Intel x86 处理器中那样受到限制。注意该对话框右下角的处理器列表。默认情况下,所有的可用处理器都被选中。由于现在的目标只是仿真程序,因此除 Win32 (WCE emulator) 之外,清除所有的复选框,如下图所示。 |
6. |
单击 OK 启动向导。 |
7. |
在该向导的第一页中,单击 Single document,确保选定 Document/View Architecture support? 复选框,然后单击 Next,如下图所示。 选择 Document/View Architecture support? 复选框将使该向导为应用程序的主代码创建两个类。Document 类旨在保存和保持状态(数据),而 View 类提供数据的图形化表示形式。这是一种“一对多”关系,其中 Document 类可能具有多种相关视图,每个视图提供数据的一个不同的图形因素。该体系结构以数据为中心,因此,更改通知很简单,并且通过文档集中进行数据访问和存储。 |
8. |
在该向导的下一页中,保留所有的默认选项,然后单击 Next,如下图所示。 |
9. |
在该向导的下一页中,单击 Next,如下图所示。 |
10. |
在该向导的下一页中,单击 Finish,如下图所示。 |
11. |
出现摘要时,单击 OK 完成该向导,如下图所示。 |
既然已经完成该向导,您就有了一个可以部署到仿真程序并在其之上运行的应用程序,尽管它还不会做任何特别有趣的事情。
使用 Windows CE 的部分好处在于从许多设备中进行选择甚至生成自定义设备及其相关 SDK 的灵活性。在使用 eMbedded Visual C++ 开发应用程序时,您必须配置平台管理器以表明您希望将图像下载到何种平台和设备。在部署项目之前,请检查平台管理器的设置。
要配置平台管理器
1. |
单击 Build | Set Active Platform 菜单命令。 |
2. |
在对话框中,选择 STANDARDSDK_410,然后单击 OK,如下图所示。 您也可以从 WCE 配置工具栏中选择活动平台。 在这种情况下,您只能使用单个的平台。如果您已经安装更多的 SDK,此处的列表将会增加。 |
3. |
单击 Build | Set Active Configuration 菜单命令。 |
4. |
在对话框中,选择 Scribble – Win32 (WCE emulator) Debug,然后单击 OK,如下图所示。 您也可以从 WCE 配置工具栏中选择活动配置。 对于在初始向导页中选定的每种处理器类型,都会有两种相关的项目配置:调试和发布。每种配置都包含诸如编译、链接以及调试设置等信息。您可以通过 Build | Configurations 菜单创建其他配置或删除现有配置。由于只选定了仿真程序处理器,因此,您只有两种配置。 迄今为止,您已经设置了相关的信息,用于为目标设备环境生成正确的二进制图像。最后,您需要选择在何处(是物理连接的设备还是仿真程序)放置输出图像。在本文中,您只有一个可用目标,这就是仿真程序。但是对于其他 CPU 类型,则有多个选择。 |
5. |
在 WCE 配置工具栏上,选择 STANDARDSDK_410 Emulator,如下图所示。 |
现在,您就可以生成并部署第一个仿真程序应用程序。在此步骤中,该仿真程序将在桌面计算机上启动。启动过程可能需要一点时间。
要生成和部署第一个仿真程序应用程序。
1. |
单击 Build | Build Scribble.exe 菜单命令生成应用程序并将其下载到仿真程序中。 仿真程序应当启动,然后,程序应自动地下载到仿真程序中。重新编译和下载的键盘快速方式为 F7。 仿真程序屏幕应当如下图所示。 现在,您需要启动应用程序。 |
2. |
在仿真程序中,双击 My Computer 查看刚才下载的 Scribble.exe 应用程序。下图显示 My Computer 的内容。 |
3. |
双击 Scribble.exe。 应用程序启动,如下图所示。 此时,您拥有一个完整工作的应用程序 ─ 尽管它不能做太多工作! |
4. |
单击 File | Exit 退出该应用程序,如下图所示。 |
5. |
让仿真程序继续运行并切换到 eMbedded Visual C++,准备下一个练习。 |
第二部分:向应用程序中添加鼠标捕获和手写输入绘图
现在您需要向应用程序中添加一些实际的功能。在该部分的练习中,您将添加来自手写笔或鼠标的数据的捕获并将其绘制为屏幕上的手写输入。您需要探测手写笔何时接触屏幕、何时移动以及何时离开屏幕。您将逐步生成这种功能,这样就可以熟悉如何使用 MFC 向导来加快编写 Windows CE 代码的速度,并充分利用开发人员可用的 MFC 体系结构。
在该部分的练习中,您将执行以下步骤:
• | 向 CScribbleView 类中添加状态变量 |
• | 修改类构造函数 |
• | 向 CSCribbleView 类中添加 OnLButtonDown 方法启动手写输入捕获 |
• | 向 CScribbleView 类中添加 OnLButtonUp 方法停止手写输入捕获 |
• | 向 CScribbleView 类中添加 OnMouseMove 方法捕获和绘制手写输入。 |
• | 编译和测试应用程序 |
要向 CScribbleView 类中添加状态变量
1. |
在 eMbedded Visual C++ 左侧窗格的底部,单击 Class View 选项卡。 |
2. |
单击 Scribble classes 行旁边的加号 (+) 展开应用程序中的类列表。 该列表包含 5 个类,它们形成标准 MFC Doc / View 应用程序的模板。 Doc / View 应用程序的设计将应用程序分成 Document 类(保存数据)和 View 类(向用户呈现数据),如先前的练习所述。其他三个类 ─ App 类、MainFrame 类以及 AboutDlg 类 ─ 分别提供对应用程序、应用程序顶层窗口以及 About 对话框的支持。 |
3. |
右键单击 CScribbleView 类,然后单击 Add Member Variable,如下图所示。 |
4. |
在 Variable Type 框中,键入 CPoint(这是一个简化 x 坐标和 y 坐标控制的 MFC 类)。 |
5. |
在 Variable Name 框中,键入 m_CurrentPoint |
6. |
在 Access 下面,单击 Protected,如下图所示。 一种很好的习惯是,通过使用 Protected 选项限制访问来隐藏数据成员。然后,类成员函数可以读取和更新类的状态,但是外部函数和对象则不能。 m_CurrentPoint 变量保存最后一个绘图点,但是您还需要一个其他变量,来表明您是否处于绘图状态。 |
7. |
在 Add Member Variable 对话框中,单击 OK。 |
8. |
右键单击 CScribbleView 类,然后单击 Add Member Variable。 |
9. |
在 Variable Type 框中,键入 bool |
10. |
在 Variable Name 框中,键入 m_InDraw |
11. |
在 Access 下面,单击 Protected。 |
类向导将对 CScribbleView 的定义进行编辑,向该类中添加变量。您将使用该变量来表明何时需要捕获鼠标输入。
在使用类之前对其状态进行初始化始终是一种很好的习惯,因为有关构造的成员数据中保存的值并不存在自动保证。进行该初始化的最佳位置是类的构造函数,而对于内部数据类型,使用类初始化列表则是一种较好的习惯。
您需要查找类构造函数并对其进行修改以清除您的状态。
要修改类构造函数
1. |
在显示项目的类视图的左侧窗格中,单击 CScribbleView 旁边的加号 (+) 展开该类中方法和数据的列表。 |
2. |
双击带有签名 CScribbleView() 的类的默认构造函数,如下图所示。 该步骤打开 ScribbleView.cpp 文件并显示以下构造函数。 |
3. |
在大括号 ({) 之前,添加以下代码行。 : m_InDraw(false), m_CurrentPoint(0,0) |
要向 CScribbleView 类中添加 OnLButtonDown 方法启动手写输入捕获
1. |
右键单击 CScribbleView 类,然后单击 Add Windows Message Handler,如下图所示。 |
2. |
在 New Windows messages/events 列表中,选择 WM_LBUTTONDOWN,然后单击 Add and Edit,如下图所示。 该类向导将 WM_LBUTTONDOWN 函数原型添加到应用程序中,并打开该新函数的编辑器。 |
3. |
替换注释: // TODO: Add your message handler code here and/or call default 使用以下代码: m_InDraw = true; m_CurrentPoint = point; 前面的代码设置类状态,表示正在绘图并存储手写输入的起始点。 |
要向 CScribbleView 类中添加 OnLButtonUp 方法停止手写输入捕获
1. |
右键单击 CScribbleView 类,然后单击 Add Windows Message Handler。 |
2. |
在 New Windows messages/events 列表中,选择 WM_LBUTTONUP,然后单击 Add and Edit,如下图所示。 类向导将 WM_LBUTTONUP 函数原型添加到应用程序中,并打开该新函数编辑器。 |
3. |
替换注释: // TODO: Add your message handler code here and/or call default 使用以下代码: m_InDraw = false; m_CurrentPoint = CPoint(0,0); 前面的代码设置类状态,表示绘图已经停止,然后将当前点设置为 0,0。该设置是表示不存在上一点的一个特殊位置。 |
要向 CScribbleView 类中添加 OnMouseMove 方法以捕获并绘制手写输入
• | 右键单击 CScribbleView 类,然后单击 Add Windows Message Handler。 |
• | 在 New Windows messages/events 列表中,选择 WM_MOUSEMOVE,然后单击 Add and Edit,如下图所示。 类向导将 WM_MOUSEMOVE 函数原型添加到应用程序中,并打开该新函数编辑器。 |
• | 替换注释: // TODO: Add your message handler code here and/or call default 使用以下代码: if (m_InDraw) { if (point != m_CurrentPoint) { CPoint line[2]; line[0] = m_CurrentPoint; line[1] = point; m_CurrentPoint = point; CDC* pDC = GetDC(); pDC->Polyline(line, 2); ReleaseDC(pDC); } } else 在该代码中,有意没有对 else 语句进行定义,因为向导生成的代码形成 else 语句。 前面的代码检查您处于捕获模式(已经调用 WM_LBUTTONDOWN),并检查手写笔已经从之前的位置移动。然后,它生成一个两点数组 ─ 最近捕获的点和最新捕获的点 ─ 并使用当前窗口的设备上下文在它们之间绘制一条直线。 如果您不是处于绘图模式,则将通过调用 else 语句中的生成代码产生默认的操作,如下所示。 CView::OnMouseMove (nFlags, point); |
现在您可以再次测试应用程序以确保所有功能都正确无误。
要编译和测试应用程序
1. |
单击 Build | Build Scribble.exe 菜单命令(或按 F7)来生成和下载该应用程序。 |
2. |
更正任何编译器错误。 |
3. |
如果下载到仿真程序失败,进行检查以确保您现在没有运行早期版本的 Scribble.exe。 |
4. |
如果应用程序仍然在运行,单击 File | Exit 退出。 |
在新版本运行后,您应当只能通过在仿真程序上使用鼠标在应用程序中绘制直线。注意您有一些不执行任何操作的菜单命令,如果您在运行 Scribble.exe 之前加载了另外的应用程序并引起它重绘,则会丢失所有的直线信息。
记住在完成测试后退出应用程序。
第三部分:修改应用程序以存储和重绘手写输入
现在,在重绘屏幕时,直线数据丢失。您需要在 CScribbleDoc 类中添加存储变量以存储捕获的数据,并向 View 类中添加更多代码以在适当的时刻调用这些方法。
在本部分的练习中,您将执行以下步骤:
• | 向 CScribbleDoc 类中添加手写输入的类型定义 |
• | 向其他头文件中添加引用 |
• | 使用 stdafx.h 生成预编译头 |
• | 向 CScribbleDoc 类中添加手写输入数据的存储 |
• | 向 CScribbleDoc 类中添加 GetFirstLine 方法 |
• | 向 CScribbleDoc 类中添加 GetNextLine 方法 |
• | 向 CScribbleDoc 类中添加 StartNewLine 方法 |
• | 向 CScribbleDoc 类中添加 AddPoint 方法 |
• | 为当前直线向 CScribbleView 中添加存储变量 |
• | 修改 CScribbleView::OnLButtonDown以引用 CScribbleDoc |
• | 修改 CScribbleView::OnMouseMove以引用 CScribbleDoc |
• | 向 CScribbleView::OnDraw 中添加实现 |
• | 编译和测试应用程序 |
要向 CScribbleDoc 类中添加手写输入的类型定义
1. |
在 eMbedded Visual C++ 的左侧窗格底部,单击 Class View 选项卡。 |
2. |
右键单击 CScribbleDoc 类,然后单击 Go to Definition,如下图所示。 |
3. |
在类定义 class CScribbleDoc : public CDocument 上面,添加以下两行。 typedef CArray < CPoint,CPoint > SingleLine; typedef CList < SingleLine *, SingleLine * > LineList; 您可以使用前面的定义把手写输入行作为点的集合,并引用手写输入行的集合。 |
CArray 和 CList 类需要默认情况下没有包括在内的其他头文件。为了能够在整个项目中使用这些类,您需要在 stdafx.h 头文件中添加对该头文件的引用。
要添加对其他头文件的引用
1. |
在 eMbedded Visual C++ 的左侧窗格底部,单击 File View 选项卡。 |
2. |
单击 Scribble Files 行旁边的加号 (+) 展开项目中的文件组列表。 |
3. |
单击 Header Files 行旁边的加号 (+) 展开应用程序中使用的头文件列表。 该列表将包含七个文件,它们形成标准 MFC Doc / View 应用程序的模板。 |
stdafx.h 文件用于生成预编译头,该预编译头将包括在项目中所有已编译的文件中。它提供一种编译项目中只使用一次的通用声明和类型的方法,以加快生成过程速度。
要使用 stdafx.h 生成预编译头
1. |
右键单击 stdafx.h file,然后单击 Open,如下图所示。 |
2. |
查找该行: #include // MFC core and standard components 只需在其下面添加该行: #include // MFC standard template classes |
如您所见,View 类负责捕获来自用户的信息,并将其显示在屏幕上。但是,Document 类负责存储和访问 View 类显示的数据。此时,还没有存储或保存数据。在以下的步骤中,您将添加为该点数据提供存储的成员变量。
要向 CScribbleDoc 类中添加手写输入数据的存储
1. |
在左侧窗格中,选择 Class View。 |
2. |
右键单击 CScribbleDoc class,然后单击 Add Member Variable,如下图所示。 |
3. |
在 Variable Type 框中,键入 LineList |
4. |
在 Variable Name 框中,键入 m_LineInfo |
5. |
在 Access 下面,单击 Protected,如下图所示。 |
6. |
单击 OK。 |
类向导对 CScribbleDoc 类的类定义进行编辑,将变量添加到该类中。由于该变量是一个保护变量,您需要添加访问方法来设置和检索该集合中的数据。
要向 CScribbleDoc 类中添加 GetFirstLine 方法
• | 在显示类定义的左侧窗格中,右键单击 CScribbleDoc 类,然后单击 Add Member Function。 |
• | 在 Function Type 框中,键入 const SingleLine * |
• | 在 Function Declaration 框中,键入 GetFirstLine (POSITION & pos) const,如下图所示。 |
• | 单击 OK。 类向导在头文件中添加公共成员函数声明,并在源文件中添加一个空的实现。然后,保留 ScribbleDoc.cpp 文件打开,现在就可以键入该方法的实现。 |
• | 将以下代码添加到 GetFirstLine 方法的实现。 const SingleLine * RetVal = NULL; pos = m_LineInfo.GetHeadPosition(); if (pos) RetVal = m_LineInfo.GetAt(pos); return RetVal; |
要向 CScribbleDoc 类中添加 GetNextLine 方法
1. |
在显示类定义的左侧窗格中,右键单击 CScribbleDoc 类,然后单击 Add Member Function。 |
2. |
在 Function Type 框中,键入 const SingleLine * |
3. |
在 Function Declaration 框中,键入 GetNextLine ( POSITION & pos) const,如下图所示。 |
4. |
单击 OK。 |
5. |
键入 GetNextLine 方法的以下实现。 const SingleLine * RetVal = NULL; if (pos) RetVal = m_LineInfo.GetNext(pos); return RetVal; |
要向 CScribbleDoc 类中添加 StartNewLine 方法
• | 在显示类定义的左侧窗格中,右键单击 CScribbleDoc 类,然后单击 Add Member Function。 |
• | 在 Function Type 框中,键入 POSITION |
• | 在 Function Declaration 框中,键入 StartNewLine ( CPoint StartPoint ),如下图所示。 |
• | 单击 OK。 |
• | 键入 StartNewLine 方法的以下实现。 SingleLine * NewLine = new SingleLine(); NewLine->Add(StartPoint); return m_LineInfo.AddTail(NewLine); |
要向 CScribbleDoc 类中添加 AddPoint 方法
1. |
在显示类定义的左侧窗格中,右键单击 CScribbleDoc 类,然后单击 Add Member Function。 |
2. |
在 Function Type 框中,键入 bool |
3. |
在 Function Declaration 框中,键入 AddPoint ( POSITION pos, CPoint NewPoint ),如下图所示。 |
4. |
单击 OK。 |
5. |
键入 AddPoint 方法的以下实现。 SingleLine * WorkLine = m_LineInfo.GetAt(pos); WorkLine->Add(NewPoint); return true; |
既然您拥有文档中管理的数据,则需要修改现有的视图方法,从而在文档中更新和存储数据。您需要在视图中使用新的类变量来标识正在绘制的直线。
要为当前直线向 CScribbleView 中添加存储变量
1. |
在显示类定义的左侧窗格中,右键单击 CScribbleView 类,然后单击 Add Member Variable,如下图所示。 |
2. |
在 Variable Type 框中,键入 POSITION |
3. |
在 Variable Name 框中,键入 m_CurrentPos |
4. |
在 Access 下,单击 Protected,如下图所示。 |
5. |
单击 OK。 |
要修改 CScribbleView::OnLButtonDown以引用 CScribbleDoc
1. |
在显示为 View 类定义的当前成员列表的左侧窗格中,双击 OnLButtonDown 方法,如下图所示。 |
2. |
在调用基类 CView::OnLButtonDown(nFlags, point) 之前,对实现进行修改,在该方法结尾添加如下代码。 m_CurrentPos = GetDocument()->StartNewLine(point); 该步骤检索与视图相关的当前文档,并调用早先定义的 StartNewLine 方法。 |
现在您需要修改 OnMouseMove 方法。
要修改 CScribbleView::OnMouseMove以引用 CScribbleDoc
1. |
在显示为 CScribbleView 类定义的当前成员列表的左侧窗格中,双击 OnMouseMove 方法转到其实现。 |
2. |
对该实现进行修改,紧接 ReleaseDC(pDC) 之后添加以下代码。 GetDocument()->AddPoint(m_CurrentPos, point); |
现在您拥有存储在文档中的点数据,该数据在捕获输入时会正确地从 View 类中进行更新。要做的下一个步骤是使该数据被擦除时可以在屏幕上重绘。要重绘该数据,您需要修改 OnDraw 方法使客户区为空白以及执行其他操作。您将从文档中记取每条直线,而且对于每条直线,要在直线上的各点之间绘制。
要将实现添加到 CScribbleView::OnDraw
1. |
在显示为 CScribbleView 类定义的当前成员列表的左侧窗格中,双击 OnDraw 方法以转到其实现。 |
2. |
替换以下行: // TODO: add draw code for native data here 使用该代码: // Redraw the lines POSITION WorkPos; const SingleLine *WorkLine = GetDocument()->GetFirstLine(WorkPos); while (NULL !=WorkLine) { // Build an array of points and draw them if (0 ==WorkLine->GetSize()) break; CPoint * PointArray = new CPoint [WorkLine->GetSize()]; for (int x = 0;x < WorkLine->GetSize();x++) PointArray[x] = WorkLine->operator [] (x); pDC->Polyline(PointArray, x); delete [] PointArray; PointArray = NULL; WorkLine = GetDocument()->GetNextLine(WorkPos); } |
现在您就可以再次测试应用程序以确保所有功能正确无误。
要编译和测试应用程序
1. |
单击 Build | Build Scribble.exe 菜单命令(或按 F7)生成并下载该应用程序。 |
2. |
更正任何编译器错误。 |
3. |
如果下载到仿真程序失败,检查以确保您现在没有运行早期版本的 Scribble.exe。 |
4. |
如果应用程序仍然在运行,单击 File | Exit 退出。 |
在运行新版本后,您应当只能在仿真程序上使用鼠标在应用程序中绘制直线。对于该新版本,您可以启动其他应用程序然后退出,查看 Scribble.exe 重绘其手写输入。
记住在完成测试之后退出应用程序。
第四部分:探索 eMbedded Visual C++ 的调试功能
既然应用程序可以进行一些操作,而不仅仅是运行向导生成的代码,您就可以开始考虑 eMbedded Visual C++ 为设备和嵌入式解决方案的实际应用程序开发人员提供的一些主要优点。其中这些类型的解决方案明显不同于桌面计算机开发的一个主要方面,就是提供了调试和诊断工具。桌面环境受益于大量将其本质目标定位于相同硬件、使用相同操作系统功能的开发人员,因此,在过去的几年中,已经创建了大量的工具以帮助进行应用程序开发。对于设备开发人员,该领域的工具则是凤毛麟角。在本文的该部分中,您将使用 eMbedded Visual C++ 提供的一些工具。
迄今为止,您已经使用 eMbedded Visual C++ 编译应用程序并将其下载到仿真程序中,然后直接在仿真程序中运行该应用程序。在本部分的练习中,您将执行以下步骤:
• | 使用内置调试器运行应用程序 |
• | 停止调试器 |
• | 测试断点 |
• | 添加监视项 |
• | 测试监视项 |
• | 访问其他调试窗口 |
• | 在运行时修改变量的值 |
要使用内置调试器运行应用程序
• | 从 eMbedded Visual C++ 菜单中,单击 Build | Start Debug | Go,如下图所示。 您也可以按下 F5 执行该命令。 |
调试器连接到仿真程序,检查文件版本以及在仿真程序上启动应用程序。eMbedded Visual C++ 环境切换到调试模式,并查找如下图所示的内容。
在该模式中,您可以从主应用程序标题栏查看当前正在运行的应用程序。当前的自动变量位于窗口的左下侧部分(在前面的图形中没有变量,因为应用程序正在运行)。当前的监视变量位于窗口的右下侧部分(在前面的图形中没有变量,因为没有选定任何变量)。
为了使用不同的选项,您需要在某个位置停止调试器。要停止调试器,您可以使用 Build | Break 命令(如果没有系统代码正在运行),或者您可以设置断点并等待中断事件发生。
要停止调试器
1. |
从菜单栏中,单击 Edit | Breakpoints 加载断点窗口,如下图所示。 您也可以按下 ALT+F9 执行该命令。 在 Breakpoints 对话框中,您可以从三种主要的表达式类别进行中断:从位置中断(Location 选项卡);当数据表达式评估为真时中断(Data 选项卡);或者窗口过程检索某个 Windows 消息时中断(Message 选项卡),这是前两种类别的组合。在应当发生中断时,可能会使用该对话框来设置复杂条件。但是,注意使用数据表达式可能会严重地影响目标环境的性能,因为在每个指令后必须对该数据进行评估。 在该过程中,您将根据位置来设置断点。 |
2. |
在 Break at 框中,键入 CScribbleView::OnLButtonUp如下图所示。 |
3. |
单击 OK。 |
现在,您拥有一个断点设置,在从窗口释放鼠标左按钮时,将会出现该断点设置。在运行应用程序之前,在编辑器中将不会图形化显示有关一个方法的断点,因为在该断点之前调试器无法解释函数名。但是,您可以设置有关特定行的断点,该特定行将导致在编辑过程中显示一个图形化提示。F9 键是设置和清除基于位置的断点的键盘快捷方式
现在您可以使用该应用程序并查看断点的工作。
要测试断点
1. |
切换到仿真程序。 |
2. |
使用鼠标在仿真程序中绘制一条直线,然后释放鼠标按钮。 您将看到下图所示的代码。 在前面的图示中,红圈表示断点,黄色的箭头显示执行的下一条语句。 |
在开发环境的左下侧窗格中,现在您可以看到 Auto、Locals 以及 this 选项卡的相关数据。要添加监视项,您只需将它们从左下侧窗格拖放到右下侧窗格,或者也可以直接添加。下图显示 Auto 选项卡。
要添加监视项
• | 在 Auto 选项卡中,查找 m_InDraw,然后将其拖放到监视窗格。 |
要查看监视项如何工作,您可以单步执行。
要测试监视项
• | 从菜单栏中,单击 Build | Step Over。 您也可以按下 F10 执行该命令。 m_InDraw 的值变为 0 并出现红色,表示它在最后的操作中发生了变化。 |
还有其他几个有用的应用程序调试窗口。
要访问其他的调试窗口
• | 单击 View | Debug Windows | Call Stack,如下图所示。 |
查看调用堆栈、内存、寄存器以及反汇编。注意仿真程序、寄存器和反汇编均为 x86 特性。对于其他处理器类型,您可以查看与目标 CPU 相关的寄存器以及显示目标 CPU 指令集的反汇编。
现在您可以尝试一些高级功能。
要在运行时修改变量的值
1. |
单击 Edit | Breakpoints 显示断点对话框。 您也可以按下 ALT+F9 执行该命令。 |
2. |
单击 Remove All 清除所有断点。 |
3. |
单击 OK。 |
4. |
单击 Debug | Go 继续运行应用程序,如下图所示。 您也可以按下 F5 执行该命令。 下一个步骤,您将设置有关 OnMouseMove 方法的第一行的断点。 |
5. |
在源代码中向下滚动几行到 CScribbleView::OnMouseMove方法。 |
6. |
将插入符号放置到第一行 ─ if (m_InDraw) ─ 然后按下 F9 启用断点。 |
7. |
切换回仿真程序,并将鼠标移动到 Scribble 窗口上(无需按下鼠标左键)。 如下图所示,调试器应当在 OnMouseMove 方法设置断点的第一行处中断。黄色箭头显示当前行。 现在,您将使用 QuickWatch 来查看 m_InDraw 的值并将该值更改为 True。 |
8. |
将插入符号放置到 m_InDraw 变量,然后单击 Debug | Quick Watch 打开 QuickWatch 对话框(如下图所示)。 您也可以按下 SHIFT+F9 执行该命令。 |
9. |
在 Value 域中单击,将值从 0 更改为 ,然后单击 Recalculate。 |
10. |
单击 Close。 |
11. |
从菜单中单击 Debug | Step Over 移动到下一个语句。 您也可以按下 F10 执行该命令。 由于已经动态地更改了变量的值,因此您已经更改了行为,这样,现在调用绘图代码而不是将其忽略。 |
12. |
从菜单中单击 Edit | Breakpoints 显示 Breakpoints 对话框。 您也可以按下 ALT+F9 执行该命令。 |
13. |
单击 Remove All。 |
14. |
单击 OK。 |
15. |
从菜单中单击 Debug | Go 或按下 F5 继续执行。 现在,在您返回到仿真程序屏幕时,移动鼠标将导致绘制手写输入,就像按下鼠标按钮一样。 |
16. |
单击 File | Exit 退出应用程序并终止调试。 |
该操作完成第四部分和本文的主要活动。如果还有时间,可以转到第五部分。
第五部分:添加代码保存和打开手写输入文档
应用程序中仍然有未使用的菜单命令。在本部分中,您将完成应用程序,从而使它支持 File | Save As、File | New 和 File | Open 命令。
在本部分的练习中,您将执行以下步骤:
• | 修改保存和打开的文件类型 |
• | 修改 File| New 行为以清除数据结构 |
• | 修改 File | Open 和 File | Save As 行为以对数据进行系列化 |
• | 编译和测试应用程序 |
首先,您需要修改保存和打开模板,以识别与 scribble 数据相关的文件扩展名。
要修改保存和打开的文件类型
1. |
在 eMbedded Visual C++ 左侧窗格的底部,单击 Resource 选项卡。 |
2. |
单击 Scribble resources 行旁边的加号 (+),展开应用程序中包含的资源列表。 该列表包含当前项目中的七种类别的资源。 |
3. |
单击 String Table 旁边的加号 (+),展开项目中的字符串表列表,如下图所示。 |
4. |
双击 English (U.S.)。 第一项包含用于生成 doc/view 模板项的字符串。该字符串是一个特定的、由新行分隔的、包含七个子字符串标识的格式字符串(按顺序):Window Title、Document Name、File New name、filter name、filter extension、Registry file type ID 以及 Registry file type name。有关每个项的详细描述,请参阅 CDocTemplate::GetDocString 在线文档。 |
5. |
双击该项修改字符串表中 ID 为 IDR_MAINFRAME 和值为 128 的第一项。 |
6. |
将字符串更改为 Scribble\n\nScribble\nInk Doc (*.ink)\n.ink\nScribble.Document\nScribble Document,如下图所示。 |
7. |
按下 ENTER 关闭对话框。 |
要修改 File | New 行为以清除数据结构
1. |
在 eMbedded Visual C++ 左侧窗格的底部,单击 Class View 选项卡。 |
2. |
如果该类不可见,单击 Scribble classes 行旁边的加号 (+)。 |
3. |
定位到 CScribbleDoc 并在必要时单击加号 (+) 将其展开。 |
4. |
双击 OnNewDocument 方法。 |
5. |
替换下面的行: // TODO: add reinitialization code here // (SDI documents will reuse this document) 使用该代码: // Clear the document contents POSITION WorkPos = m_LineInfo.GetHeadPosition(); while (NULL !=WorkPos) delete m_LineInfo.GetNext(WorkPos); m_LineInfo.RemoveAll(); |
MFC 提供了一种可靠的结构体系来简化应用程序编写。在编写保存和打开例程时可以查看该好处的详细示例。在此情况下,您只需修改文档类的一个方法(Serialize 方法)。大多数 MFC 基元都支持 Serialize 并使该任务更简单。
要修改 File | Save As 和 File | Open 行为以序列化数据
1. |
在文档中向下滚动定位到 Serialize 方法。 |
2. |
替换下面的行: // TODO: add storing code here 使用该代码: ar << m_LineInfo.GetCount(); // Serialize the document contents POSITION WorkPos = m_LineInfo.GetHeadPosition(); while (NULL !=WorkPos) m_LineInfo.GetNext(WorkPos)->Serialize(ar); 替换下面的行: // TODO: add loading code here 使用该代码: long ElementCount; ar >> ElementCount; for (long countPos = 0; countPos < ElementCount; countPos ++) { SingleLine * NewLine = new SingleLine(); NewLine->Serialize(ar); m_LineInfo.AddTail(NewLine); } |
现在您就可以再次测试应用程序,以确保所有功能正确无误。
要编译和测试应用程序
1. |
单击 Build | Build Scribble.exe 菜单命令(或按 F7)生成并下载应用程序。 |
2. |
更正任何编译器错误。 |
3. |
如果下载到仿真程序失败,进行检查以确保您现在没有运行早期版本的 Scribble.exe。 |
4. |
如果应用程序仍然在运行,单击 File | Exit 退出。 |
运行新版本之后,您应当能够在屏幕上绘制手写输入,然后单击 File | Save As 打开显示保存选项的对话框。保存文件后,您可以单击 File | New 清除内容,然后单击 File | Open 打开以前保存的绘图。
记住完成测试后退出应用程序。
小结
以下是本文所提供练习的小结:
• | 创建了用于 Windows CE 4.1 仿真程序的 MFC 应用程序 |
• | 向应用程序中添加了鼠标捕获和手写输入绘图 |
• | 修改了应用程序以存储和重绘手写输入 |
• | 探索了 eMbedded Visual C++ 的调试功能 |
• | 添加了保存和打开手写输入文档的代码 |
转到原英文页面