单击"finish"完成工程创建
接下来我们向应用程序添加触控支持,表现以下两点:
1.我们正在构建的应用程序需要支持触控的硬件,因此我们需要在应用程序中查看这一点。
2.在 Scratchpad.cpp 中,在 CScratchPadApp::InitInstance(): 后添加以下检查代码:
- BYTE digitizerStatus = (BYTE) GetSystemMetrics(SM_DIGITIZER);
- if ((digitizerStatus & (0x80 + 0x40)) == 0)
- //堆栈就绪+多触点
- {
- AfxMessageBox(L"No touch input is currently available.");
- return false;
- }
- BYTE nInputs = (BYTE) GetSystemMetrics(SM_MAXIMUMTOUCHES);
- CString str;
- str.Format(L"Touch input available with %d touch points.", nInputs);
- AfxMessageBox(str);
- return true;
3. 您可以看到,除了查看触控可用性和就绪情况以外,我们还可以发现硬件支持的触控输入数量。
4. 编译并运行。
5. 根据机器上触控输入的数量,您应该看到类似下图的输出:
6.为了注册应用程序客户端视图窗口来接收触控消息,我们需要调用 MFC 函数 CWnd::RegisterTouchWindow()。我们将在视图创建之后执行该操作,即在 OnCreate() 事件处理程序中完成。
切换到 Class View 并选择 CChildView 类。
在 Properties 页面中,转到 Message 属性表并导航到 WM_CREATE,然后从下拉框中添加 OnCreate() 消息处理程序:
7. 在 CChildView::OnCreate() 处理程序中添加以下代码,注册视图窗口的触控输入:
- if (!RegisterTouchWindow())
- {
- ASSERT(FALSE);
- }
注意:调用 CWnd::RegisterTouchWindow() 注册(和注销)窗口,使其具有触控功能,允许接收低级 WM_TOUCH 消息。
8. 因为我们注册了视图来接收触控输入,我们必须重写接收每个触控消息的处理程序:CWnd::OnTouchInput()。
该处理程序接收来自 Windows Touch 的单个输入,并在应用程序处理该消息时返回 TRUE;否则返回 FALSE。
9.在 ChildView.h 中添加该方法声明:
- // 重写
- protected:
- virtual BOOL OnTouchInput(CPoint pt, int nInputNumber, int nInputsCount, PTOUCHINPUT pInput);
10.在 ChildView.cpp 中提供相应的实现:
- BOOL CChildView::OnTouchInput(CPoint pt, int nInputNumber, int nInputsCount, PTOUCHINPUT pInput)
- {
- // 在此处输入消息处理Tocuh
- return false;
- }
然后我们向项目添加笔画源和头文件,并使用手指绘制线条
我们希望将手指作为多输入设备。我们希望为每个触摸屏幕的手指绘制一条线。为此,我们将使用两个笔画集合。一个集合保存完成的笔画(线条),另一个集合保存正在绘制的线条。触摸屏幕的每个手指都指向 m_StrkColDrawing 集合中的笔画。当我们从屏幕拿开手指时,我们将手指的笔画从m_StrkColDrawing 移动到 m_StrkColFinished 集合。此外,如果用户在多点触控监视器上使用两个以上的手指,我们希望笔画有不同的颜色。
1. 在 Starter 文件夹中,您将找到两个文件:Stroke.h 和 Stroke.cpp。将它们复制到项目文件夹下并使用“Add Existing item…”将其添加到项目中。
2. 类似地,向项目添加 StrokeCollection.h 和 StrokeCollection.cpp。
3. 将 "Stroke.h" 和 "StrokeCollection.h" 放在 StdAfx.h 头文件结束处。
#include "Stroke.h"
#include "StrokeCollection.h"
4. 将这些私有成员变量定义添加到 ChildView.h 中:
- private:
- int m_iCurrColor; // 当前笔触的颜色
- CStrokeCollection m_StrkColFinished; // 用户完成输入笔画,接触笔触焦点
- CStrokeCollection m_StrkColDrawing; // 收集用户当前的绘图笔画
5.重要:我们必须初始化当前颜色。我们将在 ChildView.cpp 的 CChildView 构造函数中完成该操作:
- CChildView::CChildView() :m_iCurrColor(0)
- {
- }
6. 要绘制完成的集合,我们将以下调用添加到 CChildView::OnPaint() 处理程序的末尾。它将绘制所有已完成的笔画。
m_StrkColFinished.Draw(&dc);
7. 我们需要处理所有接收到的触控输入消息,因此我们处理感兴趣的所有事件:touch input down、move 和 up。
8. 在 CChildView.h 中,声明以下方法,我们将用来处理不同的触控输入事件:
protected:
- // 不同触摸输入事件的处理程序
- BOOL OnTouchInputDown(CPoint pt, PTOUCHINPUT pInput);
- BOOL OnTouchInputMove(CPoint pt, PTOUCHINPUT pInput);
- BOOL OnTouchInputUp(CPoint pt, PTOUCHINPUT pInput);
9.在 CChildView.cpp 中,添加每个触控输入处理程序的实现:
- BOOL CChildView::OnTouchInputDown(CPoint pt, PTOUCHINPUT pInput)
- {
- // 创建新的画笔,并为他添加指针
- COLORREF strokeColor = GetTouchColor((pInput->dwFlags & TOUCHEVENTF_PRIMARY) != 0);
- CStroke* pStrkNew = new CStroke(pInput->dwID, strokeColor);
- pStrkNew->Add(pt);
- // 添加新的笔触收集画板中的笔画
- m_StrkColDrawing.Add(pStrkNew);
- return true;
- }
- BOOL CChildView::OnTouchInputMove(CPoint pt, PTOUCHINPUT pInput)
- {
- // 在绘图查找笔画收集笔触。
- int strokeIndex = m_StrkColDrawing.FindStrokeById(pInput->dwID);
- if (strokeIndex >= 0)
- {
- CStroke* pStrk = m_StrkColDrawing[strokeIndex];
- // 增加笔画触摸点
- pStrk->Add(pt);
- // 绘制最后的笔画
- pStrk->Draw(GetDC());
- }
- return true;
- }
- BOOL CChildView::OnTouchInputUp(CPoint pt, PTOUCHINPUT pInput)
- {
- // 在绘图查找笔画收集笔触.
- int strokeIndex = m_StrkColDrawing.FindStrokeById(pInput->dwID);
- if (strokeIndex >= 0)
- {
- CStroke* pStrkCopy = m_StrkColDrawing[strokeIndex];
- // 从绘图上移除笔画.
- m_StrkColDrawing.RemoveAt(strokeIndex);
- // 在已经完成的笔画中增加一画.
- m_StrkColFinished.Add(pStrkCopy);
- }
- return true;
- }
10.在 CChildView.cpp 中,修改 CChildView::OnTouchInput() 的实现,以根据需要调用每个触控输入处理程序:
- BOOL CChildView::OnTouchInput(CPoint pt, int nInputNumber, int nInputsCount, PTOUCHINPUT pInput)
- {
- if ((pInput->dwFlags & TOUCHEVENTF_DOWN) == TOUCHEVENTF_DOWN) // 触摸按下事件
- {
- return OnTouchInputDown(pt, pInput);
- }
- else if ((pInput->dwFlags & TOUCHEVENTF_MOVE) == TOUCHEVENTF_MOVE) // 触摸移动事件
- {
- return OnTouchInputMove(pt, pInput);
- }
- else if ((pInput->dwFlags & TOUCHEVENTF_UP) == TOUCHEVENTF_UP) // 触摸移动事件
- {
- return OnTouchInputUp(pt, pInput);
- }
- return false;
- }
11.注意,调用了 GetTouchColor() 方法,但它尚未实现。当用户移动应用程序窗口上的多个手指时,该方法负责处理钢笔的颜色。在 CChildView.h 中添加该方法的声明:
private:
COLORREF GetTouchColor(bool bPrimaryContact);
12.以下是 CChildView.cpp 的实现:
- COLORREF CChildView::GetTouchColor(bool bPrimaryContact)
- {
- static COLORREF c_arrColor[] = // 数组中的颜色
- {
- RGB(255, 0, 0), // 红
- RGB(0, 255, 0), // 绿
- RGB(0, 0, 255), // 蓝
- RGB(0, 255, 255), // 青
- RGB(255, 0, 255), // 品红
- RGB(255, 255, 0) // 黄
- };
- COLORREF color;
- if (bPrimaryContact)
- {
- // 主要接触中绘制黑色.
- color = RGB(0,0,0); // 黑
- }
- else
- {
- // 保存当前的次要颜色.
- color = c_arrColor[m_iCurrColor];
- // 移动到数组中的下一个颜色
- m_iCurrColor = (m_iCurrColor + 1) % (sizeof(c_arrColor)/sizeof(c_arrColor[0]));
- }
- return color;
- }
13.最后,由于我们已经动态创建了许多笔画,我们需要确保每个笔画在应用程序退出之前都被销毁,因此我们在 CChildView 的析构函数中包含以下内容:
- CChildView::~CChildView()
- {
- for (int i = 0; i < m_StrkColDrawing.GetCount(); ++i)
- {
- delete m_StrkColDrawing[i];
- }
- for (int i = 0; i < m_StrkColFinished.GetCount(); ++i)
- {
- delete m_StrkColFinished[i];
- }
- }
14.现在编码部分已经全部完成,可以开始实验刚才实现的应用程序了。
15.编译并运行应用程序。它应该如下所示: