14.4.3 使用鼠标绘图(1)
对于WM_LBUTTONDOWN消息,我们希望把鼠标指针的当前位置作为定义元素的第一个点记录下来,还希望记录鼠标移动后光标的位置。存储这些信息的地方显然是CSketcherView类,所以可以添加数据成员到这个类中。在Class View窗格中右击CSketcherView类名,从弹出式菜单中选择Add | Add Variable菜单项,然后可以把需要添加的变量的细节添加到这个类中,如图14-11所示。

类型的下拉列表只包括基本类型,所以必须把变量类型输入为CPoint。新的数据成员应当是protected类型,以防止从这个类的外面对它进行直接修改,所以在列表中把Access值改为protected。单击Finish按钮,输入名称m_FirstPoint,则创建了这个变量,在这个构造函数的初始化列表中,这个变量的初始值被任意设置为0。由于需要把这个初始值修改为CPoint(0,0),因此CSketcherView.cpp中的代码如下:
- CSketcherView::CSketcherView(): m_FirstPoint(CPoint(0,0))
- {
- // TODO: add construction code here
- }
这将在位置(0,0)处把数据成员m_FirstPoint初始化为CPoint对象。现在可以把m_SecondPoint作为CPoint类型的保护成员添加到CSketcherView类中,用于存储元素的下一个点。并修改构造函数的初始列表,将其初始化为CPoint(0,0)。
现在实现WM_LBUTTONDOWN消息的处理程序:
- void CSketcherView::OnLButtonDown(UINT nFlags, CPoint point)
- {
- m_FirstPoint = point; // Record the cursor position
- }
这段代码仅仅记录第二个参数传递的坐标。在这种情况下,可以完全忽略第一个参数。
虽然现在还不能完成WM_MOUSEMOVE消息处理程序,但是可以尝试概括地写出它的代码:
- void CSketcherView::OnMouseMove(UINT nFlags, CPoint point)
- {
- if(nFlags & MK_LBUTTON) // Verify the left button is down
- {
- m_SecondPoint = point; // Save the current cursor position
- // Test for a previous temporary element
- {
- // We get to here if there was a previous mouse move
- // so add code to delete the old element
- }
- // Add code to create new element
- // and cause it to be drawn
- }
- }
检查鼠标左键是否按下是非常重要的,因为现在只希望处理这种情况下的鼠标移动。如果不进行检查,那么在处理事件时有可能是鼠标右键处于按下状态,或者鼠标在移动时没有按下任何键。
如果按下了鼠标左键,就保存当前鼠标指针位置。这是元素的第二个定义点。剩下的事情通常就很清楚了,但是在完成这个函数之前,还需要确定一些事情。现在还没有办法定义元素-- 由于我们想把一个元素定义成类的对象,因此必须定义一些类。另外还需要设计一种方法,以便在创建一个新元素时,删除原来的元素,而绘制新的元素。下面简短地介绍一些相关内容。
1. 重新绘制工作区
绘制或删除元素牵涉到重新绘制窗口的整个或部分工作区。如前所述,工作区是由CSketcherView类的OnDraw()成员函数绘制的,当Sketcher应用程序接收到WM_PAINT消息时,将调用这个函数。除了提供重新绘制工作区的基本消息以外,Windows还提供了需要重新绘制的那部分工作区的信息。在显示复杂的图像时,这可以节省大量时间,因为只需要重新绘制指定的区域,它可能只是整个区域的一个很小的部分。
通过调用视图类的成员函数InvalidateRect(),可以告知Windows应当重新绘制的特定区域。这个函数接受两个参数,第一个参数是指向RECT或CRect对象的指针,这些对象在需要重新绘制的工作区中定义矩形。如果这个参数的值是空值,那么将重新绘制整个工作区。第二个参数是BOOL值,如果准备擦除矩形的背景,那么这个BOOL值是TRUE,否则为FALSE。这个参数的默认值是TRUE,因为在重新绘制矩形前,通常需要擦除背景,这样就可以在大部分时间里忽略它。
需要重新绘制工作区的典型情况是由于某件事情发生了变化,从而必须重新创建工作区的内容。例如,在工作区中移动了一个已显示的实体。在这种情况下,需要擦除背景,以便在绘制新实体前删除已显示实体的旧图像。如果希望在已有背景的顶部绘图,只需要把FALSE作为第二个参数传递到InvalidateRect()函数。