摘  要 根据应用软件的需要,提出了蚂蚁线实现的功能需求,采用GDI++/GDI、多线程技术编程设计实现了蚂蚁线种类、绘制、属性管理类;讨论了GDI++/GDI实现方法的区别;采用线程同步、信号事件等技术实现的蚂蚁线易于扩展、运行稳定、可靠。 
关键词 蚂蚁线;流动;GDI/GDI++;线程 
   
一、引言 
图形图像处理软件中经常要进行区域、图元的选择,以往都是一些静态的直线选择块,单一而且呆板。实现软件中的流动性选择线(框)可为软件增添不少光彩。流动性选择线(框),也称蚂蚁线,就是类似Photoshop软件中选取区域时候显示的线条,像蚂蚁一样不停地流动,如下图所示,某应用软件中选择对象后,“小蚂蚁”不停地爬动, 
 
 
  
图1 应用软件中的蚂蚁线 
如下图所示,即黑色线段按照一定方向不停地移动(矩形为一个选择框)。 
 
 
  
图2 流动选择框(蚂蚁线) 
目前各种媒体上所见到的都是采用Delphi、.NET C#(参见文献2)实现,尚不见Visual C的完整实现,本文通过分析相关商业软件,用Visual C++完全实现了商业软件中蚂蚁线的功能。 
二、功能 
(1)同时管理多个蚂蚁线; 
(2)支持多种蚂蚁线,线、矩形、椭圆、曲线等; 
(3动态修改蚂蚁线的属性,如线型、颜色、宽度等; 
(4)支持线两端的属性,如圆形、矩形等; 
(5)使用方便、易于管理。 
本文实现的蚂蚁线在某矢量图形系统中得到应用,实践证明运行稳定、可靠。 
三、设计 
为了实现以上功能,共设计了两种类:蚂蚁线种类类(CMarchingAntsType)和蚂蚁线管理类(CMarchingAntsManager)。如表1所示。 
表1 蚂蚁线类定义 
| 
 CMarchingAntsType  | 
 蚂蚁线种类的基类  |  
| 
 CMarchingAntsPolyLine  | 
 折线蚂蚁线类  |  
| 
 CMarchingAntsPoints  | 
 点蚂蚁线类  |  
| 
 CMarchingAntsManager  | 
 蚂蚁线管理类  |    
为了实现不同种类的蚂蚁线,从CMarchingAntsType继承了两个类:CMarchingAntsPolyLine(折线蚂蚁线类)和CMarchingAntsManager(蚂蚁线管理类)。继承关系如图3所示。
   
 
 
  
图3 继承关系  
四、蚂蚁线种类类 
1.蚂蚁线种类的基类(CMarchingAntsType) 
为了方便实现不同的蚂蚁线,定义了一个基类CMarchingAntsType,这个基类定义了蚂蚁线的基本属性,绘制方法定义成虚函数virtual void Draw(Graphics *graphics)=0(virtual void Draw(HDC hDC)=0),两个绘制函数分别对应GDI++和GDI的绘制方法。这个类存在虚函数不能直接实例化。主要的属性如表2所示。 
表2蚂蚁线种类的基类属性 
| 
 unsigned int width  | 
 线宽  |  
| 
 float dash_length  | 
 虚线长度  |  
| 
 float space_length  | 
 空线长度  |  
| 
 unsigned int dash_color  | 
 虚线颜色  |  
| 
 unsigned int space_color  | 
 空线颜色  |  
| 
 unsigned int LineHeadType  | 
 线端点类型  |  
| 
 unsigned int LineHeadSize  | 
 线端点矩形尺寸  |  
| 
 float offst  | 
 偏移量  |  
| 
 REAL m_DashOffset  | 
 虚线偏移量  |  
| 
 int m_MaxDistance  | 
 最大距离  |  
| 
 bool b_DirectionFlag  | 
 移动方向  |  
| 
 CRITICAL_SECTION cs  | 
 互斥量  |  
| 
 HDC m_hDC  | 
 绘图句柄  |    
2. 折线蚂蚁线类(CMarchingAntsPolyLine) 
CMarchingAntsPolyLine类实现了有关折线(由一系列线段组成)的蚂蚁线,存储了折线的坐标串Point *point(//坐标数组)和unsigned int count(//坐标数量),最为关键的是重载了绘制函数Draw(),实现了折线蚂蚁线的实质性绘制。 
void Draw(Graphics *graphics)的关键代码如下: 
//分别产生虚线和空线画笔、设置画笔属性 
Pen m_DashPen(…); 
Pen m_SpacePen((…); 
m_DashPen.SetWidth(REAL(GetWidth())); 
m_SpacePen.SetWidth(REAL(GetWidth())); 
m_DashPen.SetDashStyle(DashStyleCustom); 
REAL dashVals[4] = { 
    REAL(GetDashLength()),   //虚线长度 
    REAL(GetSpaceLength()),   //空线长度 
    REAL(GetDashLength()),  
    REAL(GetSpaceLength())}; 
//设置虚线和空线长度参数m_DashPen.SetDashPattern(dashVals, 4); 
//设置开始到虚线的长度,这是实现蚂蚁 
//爬动的关键步骤,通过不断修改这个值 
//和重新绘制即可实现蚂蚁不断爬动 
m_DashPen.SetDashOffset(m_DashOffset); 
//绘制 
graphics->DrawLines(&m_SpacePen,point,count); 
graphics->DrawLines(&m_DashPen,point,count); 
//绘制线的两端,如小矩形和椭圆等,可以进行扩展 
Pen myPen(Color(0,0,0)); 
SolidBrush myBrush(Color(0,255,0)); 
unsigned int i; 
switch(LineHeadType) 
… 
void Draw(HDC hDC)的关键代码如下: 
unsigned int i=0; 
int len=0; 
//分别对每条线段处理 
for(i=0;i<count-1;i++) 
{ 
    ::LineDDA(…); 
    len+=(int)sqrt(…); 
} 
if(len%((int)(GetDashLength()+GetSpaceLength()))==0) 
    m_DashOffset++; 
//绘制线的两端,如小矩形和椭圆等,可以进行扩展 
HPEN hPen=CreatePen(PS_SOLID,1,RGB(0,0,0)); 
HPEN oldPen=(HPEN)SelectObject(hDC,hPen); 
HBRUSH hBrush=CreateSolidBrush(RGB(0,255,0)); 
HBRUSH OldBrush=(HBRUSH)SelectObject(…); 
… 
GDI++和GDI的实现的区别:是在GDI中没有设置虚线离开始点距离的SetDashOffset方法,需要利用LineDDA实现,效果也与GDI++有所区别。 
LineDDA是一个32位的图形设备接口库函数调用,从如下所示的函数原形中可以看出其入口参数是一组线条坐标、一个回调函数的地址以及一个指向应用程序定义数据的指针: 
BOOL LineDDA( int nXStart, // 线条起点的X坐标 
int nYStart,        // 线条起点的Y坐标 
int nXEnd,         // 线条终点的X坐标 
int nYEnd,                 // 线条终点的Y坐标 
LINEDDAPROC lpLineFunc,   // 回调函数的指针 
LPARAM lpData              // 应用程序定义数据的指针 
  由lpLineFunc指针指向的回调函数将在除终点外的线段的每个点上被调用,显然这里是实现蚂蚁线爬动的最佳地方。该回调函数在CMarchingAntsType类中定义为VOID CALLBACK MovingDots(int X,int Y,LPARAM lpData),主要代码如下: 
//移动的量 
int count =((int)(pType->m_DashOffset)) %((int)( ……)); 
    COLORREF vColor=RGB(0,0,0); 
    if (count < pType->GetDashLength()) 
        vColor = pType->GetForeColor(); 
    else if (count < pType->GetDashLength()+pType->GetSpaceLength()) 
        vColor = pType->GetBackColor(); 
//在每点进行绘制 
SetPixel(pType->m_hDC, X, Y, vColor); 
//增加偏移量 
    pType->m_DashOffset+=1; 
3.点蚂蚁线类(CMarchingAntsPoints) 
  绘制点的蚂蚁线,实现与CMarchingAntsPolyLine类似,这里不再赘述。 
			
				 |