CodeProject - DrawTools(画图工具)

原作者: Alex Farber
原文: http://www.codeproject.com/csharp/DrawTools.asp(源代码请参见原文)

CodeProject - DrawTools(画图工具)

介绍

DrawTools示例告诉你怎么创建一个Windows窗体,来使用鼠标和画图工具在窗体上的可用区域画图。这个示例中实现了以下画图工具:矩形,椭圆形,直线和铅笔。其中有一些众所周知的技术来创建这个程序,比如说:鼠标的交互,无闪烁画图,实现了画图和工具选择,物体选择,控制物体的Z轴次序,等等。MFC开发者可以从DRAWCLI.这个MFC示例中了解到所有这些特性。DrawTools这个C#程序复制了一些DRAWCLI的功能,并且在这个例子中使用了一些设计决定。

DrawTools 解决方案包括两个工程: DrawTools 窗体应用程序和 DocToolkit 类库。 DrawTools 实现了一些特别的应用程序功能, DocToolkit 包含有一些用于文件管理的标准类库。

以下描述了DrawTools 解决方案的主要特点:

 


CodeProject - DrawTools(画图工具)
 

  • DrawArea用来填充主程序在窗体上可用区域的用户控件。包括GraphicsList 类的实例。绘制图形对象, 处理鼠标输入,把(鼠标)命令传给GraphicsList
  • GraphicsList图形对象的列表。包括图形对象的ArrayList。通过使用DrawObject类中的方法与其他图形对象通讯
  • DrawObject所有图形对象的抽象基类。
  • DrawRectangle矩形图形对象。
  • DrawEllipise椭圆形图形对象。
  • DrawLine直线图形对象。
  • DrawPolygon多边形图形对象。
  • Tool所有画图工具的抽象基类。
  • ToolPointer箭头工具 (中性工具)。包含选择,移动,改变图形对象大小的实现。
  • ToolObject所有工具的抽象基类,用来创建新的图形对象。ToolRectangle矩形工具。
  • ToolEllipse椭圆形工具。
  • ToolLine直线工具。
  • ToolPolygon多边形工具。

DocToolkit 类库

DocToolkit类库包含一些类的集合,这些类用来创建文档中心(document-centric)的窗体应用程序。从DocToolkit类库输出的类的实例被保存在DrawTools工程的主窗口中,用作一般的文件操作。  

  • DocManager : 处理文件操作:打开,新建,保存,更新窗体标题,为Windows Shell注册文件类型。创建这个类引用了Chris Sells 的文章 Creating Document-Centric Applications in Windows Forms
  • DragDropManager : 在Windows Form应用程序中允许你通过拖拽的方式从浏览器(文件浏览器)中打开文件。
  • MruManager : 管理大多数最近使用的文件列表。
  • PersistWindowState : 允许你把最近一次的窗口状态保存到注册表 ,在窗体载入的时候重新获得。来源: Saving and Restoring the Location, Size and Windows State of a .NET Form By Joel Matthias.

在程序空闲的时候操作Windows的控件状态

每一个Windows窗体应用程序都会有许多控件,比如说菜单项,按钮,工具栏按钮等等。根据当前状态和用户的命令,这些控件可能有不同的状态:enabled/disabledchecked/unchecked, visible/invisible 等等。用户的每一个操作可能改变这些状态。在每一个消息句柄中改变控件的状态可能导致错误。取而代之的方法是,在用户每一个操作后调用一些函数,在这些函数中管理控件的状态。MFC有一个很好的特性叫ON_UPDATE_COMMAND_UI它允许在应用程序的空闲时间更新工具栏按钮的状态。这个特性也可以在.NET程序中实现。


考虑一下这种情形:当用户点击工具栏上的Rectangle按钮,这个按钮就要显示为被选中,前一个激活的工具就要显示为没选中。Rectangle按钮的消息句柄并没有改变窗体控件的状态,它只是在一些变量中保存了当前的选择。空闲的消息句柄选择激活的工具,取消未激活工具的选择。


CodeProject - DrawTools(画图工具) private   void  Form1_Load( object  sender, System.EventArgs e)
CodeProject - DrawTools(画图工具)
{
CodeProject - DrawTools(画图工具)    
// Submit to Idle event to set controls state at idle time
CodeProject - DrawTools(画图工具)
    Application.Idle += new EventHandler(Application_Idle);
CodeProject - DrawTools(画图工具)}

CodeProject - DrawTools(画图工具)
CodeProject - DrawTools(画图工具)
private   void  Application_Idle( object  sender, EventArgs e)
CodeProject - DrawTools(画图工具)
{
CodeProject - DrawTools(画图工具)    SetStateOfControls();
CodeProject - DrawTools(画图工具)}

CodeProject - DrawTools(画图工具)
CodeProject - DrawTools(画图工具)
public   void  SetStateOfControls()
CodeProject - DrawTools(画图工具)
{
CodeProject - DrawTools(画图工具)    
// Select active tool
CodeProject - DrawTools(画图工具)
    tbPointer.Pushed = (drawArea.ActiveTool == DrawArea.DrawToolType.Pointer);
CodeProject - DrawTools(画图工具)    tbRectangle.Pushed 
= (drawArea.ActiveTool == DrawArea.DrawToolType.Rectangle);
CodeProject - DrawTools(画图工具)    tbEllipse.Pushed  
= (drawArea.ActiveTool == DrawArea.DrawToolType.Ellipse);
CodeProject - DrawTools(画图工具)    tbLine.Pushed 
= (drawArea.ActiveTool == DrawArea.DrawToolType.Line);
CodeProject - DrawTools(画图工具)    tbPolygon.Pushed 
= (drawArea.ActiveTool == DrawArea.DrawToolType.Polygon);
CodeProject - DrawTools(画图工具)
CodeProject - DrawTools(画图工具)    menuDrawPointer.Checked 
= 
CodeProject - DrawTools(画图工具)                      (drawArea.ActiveTool 
== DrawArea.DrawToolType.Pointer);
CodeProject - DrawTools(画图工具)    menuDrawRectangle.Checked 
= 
CodeProject - DrawTools(画图工具)                      (drawArea.ActiveTool 
== DrawArea.DrawToolType.Rectangle);
CodeProject - DrawTools(画图工具)    menuDrawEllipse.Checked 
= 
CodeProject - DrawTools(画图工具)                      (drawArea.ActiveTool 
== DrawArea.DrawToolType.Ellipse);
CodeProject - DrawTools(画图工具)    menuDrawLine.Checked 
= (drawArea.ActiveTool == DrawArea.DrawToolType.Line);
CodeProject - DrawTools(画图工具)    menuDrawPolygon.Checked 
= 
CodeProject - DrawTools(画图工具)                      (drawArea.ActiveTool 
== DrawArea.DrawToolType.Polygon);
CodeProject - DrawTools(画图工具)
CodeProject - DrawTools(画图工具)    
// CodeProject - DrawTools(画图工具)
CodeProject - DrawTools(画图工具)
}

CodeProject - DrawTools(画图工具)
CodeProject - DrawTools(画图工具)
//  Rectangle tool is selected
CodeProject - DrawTools(画图工具)
private   void  CommandRectangle()
CodeProject - DrawTools(画图工具)
{
CodeProject - DrawTools(画图工具)     drawArea.ActiveTool 
= DrawArea.DrawToolType.Rectangle;
CodeProject - DrawTools(画图工具)}

CodeProject - DrawTools(画图工具)

Hit Test

DrawObject 类有一个叫HitTest的虚拟函数,用来侦测是否Point属于图形对象。

CodeProject - DrawTools(画图工具) public   virtual   int  HitTest(Point point)
CodeProject - DrawTools(画图工具)
{
CodeProject - DrawTools(画图工具)    
return -1;
CodeProject - DrawTools(画图工具)}

CodeProject - DrawTools(画图工具)

继承类使用虚拟的PointInObject来做点击测试。这个函数调用自HitTestDrawRectangle类使用了一种简单的方法实现了这个函数:

CodeProject - DrawTools(画图工具) protected   override   bool  PointInObject(Point point)
CodeProject - DrawTools(画图工具)
{
CodeProject - DrawTools(画图工具)    
return rectangle.Contains(point);
CodeProject - DrawTools(画图工具)    
// rectangle is class member of type Rectangle
CodeProject - DrawTools(画图工具)
}

CodeProject - DrawTools(画图工具)

DrawLine对这个函数的实现更加复杂:

CodeProject - DrawTools(画图工具) protected   override   bool  PointInObject(Point point)
CodeProject - DrawTools(画图工具)
{
CodeProject - DrawTools(画图工具)    GraphicsPath areaPath;
CodeProject - DrawTools(画图工具)    Pen areaPen;
CodeProject - DrawTools(画图工具)    Region areaRegion;
CodeProject - DrawTools(画图工具)
CodeProject - DrawTools(画图工具)    
// Create path which contains wide line
CodeProject - DrawTools(画图工具)    
// for easy mouse selection
CodeProject - DrawTools(画图工具)
    AreaPath = new GraphicsPath();
CodeProject - DrawTools(画图工具)    AreaPen 
= new Pen(Color.Black, 7);
CodeProject - DrawTools(画图工具)    AreaPath.AddLine(startPoint.X, startPoint.Y, endPoint.X, endPoint.Y);
CodeProject - DrawTools(画图工具)        
// startPoint and EndPoint are class members of type Point
CodeProject - DrawTools(画图工具)
    AreaPath.Widen(AreaPen);
CodeProject - DrawTools(画图工具)
CodeProject - DrawTools(画图工具)    
// Create region from the path
CodeProject - DrawTools(画图工具)
    AreaRegion = new Region(AreaPath);
CodeProject - DrawTools(画图工具)
CodeProject - DrawTools(画图工具)    
return AreaRegion.IsVisible(point);
CodeProject - DrawTools(画图工具)}

CodeProject - DrawTools(画图工具)

DrawPolygon函数使用了同样的方法,但是AreaPath包含了多边形的所有线。

序列化

GraphicList类实现了ISerializable接口,这个接口用作类对象的二进制序列化。DrawObject类有两个虚函数用来做序列化。


CodeProject - DrawTools(画图工具) public   virtual   void  SaveToStream(SerializationInfo info,  int  orderNumber)
CodeProject - DrawTools(画图工具)
{
CodeProject - DrawTools(画图工具)    
// CodeProject - DrawTools(画图工具)
CodeProject - DrawTools(画图工具)
}

CodeProject - DrawTools(画图工具)
CodeProject - DrawTools(画图工具)
public   virtual   void  LoadFromStream(SerializationInfo info,  int  orderNumber)
CodeProject - DrawTools(画图工具)
{
CodeProject - DrawTools(画图工具)  
// CodeProject - DrawTools(画图工具)
CodeProject - DrawTools(画图工具)
}

CodeProject - DrawTools(画图工具)

这些函数在每一个继承类中都实现了。二进制文件有以下格式:

Number of objects
Type name
Object
Type name
Object
...
Type name
Object

这样就可以在GraphicList类里写普通的序列化代码,而不需要了解序列化对象的任何细节。

CodeProject - DrawTools(画图工具) private   const   string  entryCount  =   " Count " ;
CodeProject - DrawTools(画图工具)
private   const   string  entryType  =   " Type " ;
CodeProject - DrawTools(画图工具)
CodeProject - DrawTools(画图工具)
CodeProject - DrawTools(画图工具)
//  Save list to stream
CodeProject - DrawTools(画图工具)
[SecurityPermissionAttribute(SecurityAction.Demand, 
CodeProject - DrawTools(画图工具)                         SerializationFormatter
= true )]
CodeProject - DrawTools(画图工具)
public   virtual   void  GetObjectData(SerializationInfo info, 
CodeProject - DrawTools(画图工具)                                     StreamingContext context)
CodeProject - DrawTools(画图工具)
{
CodeProject - DrawTools(画图工具)    
// number of objects
CodeProject - DrawTools(画图工具)
    info.AddValue(entryCount, graphicsList.Count);
CodeProject - DrawTools(画图工具)
CodeProject - DrawTools(画图工具)    
int i = 0;
CodeProject - DrawTools(画图工具)
CodeProject - DrawTools(画图工具)    
foreach ( DrawObject o in graphicsList )
CodeProject - DrawTools(画图工具)    
{
CodeProject - DrawTools(画图工具)        
// object type
CodeProject - DrawTools(画图工具)
        info.AddValue(
CodeProject - DrawTools(画图工具)            String.Format(CultureInfo.InvariantCulture,
CodeProject - DrawTools(画图工具)                
"{0}{1}",
CodeProject - DrawTools(画图工具)                entryType, i),
CodeProject - DrawTools(画图工具)            o.GetType().FullName);
CodeProject - DrawTools(画图工具)
CodeProject - DrawTools(画图工具)        
// object itself
CodeProject - DrawTools(画图工具)
        o.SaveToStream(info, i);
CodeProject - DrawTools(画图工具)
CodeProject - DrawTools(画图工具)        i
++;
CodeProject - DrawTools(画图工具)    }

CodeProject - DrawTools(画图工具)}

CodeProject - DrawTools(画图工具)
CodeProject - DrawTools(画图工具)
//  Load from stream
CodeProject - DrawTools(画图工具)
protected  GraphicsList(SerializationInfo info, StreamingContext context)
CodeProject - DrawTools(画图工具)
{
CodeProject - DrawTools(画图工具)    graphicsList 
= new ArrayList();
CodeProject - DrawTools(画图工具)
CodeProject - DrawTools(画图工具)    
// number of objects
CodeProject - DrawTools(画图工具)
    int n = info.GetInt32(entryCount);
CodeProject - DrawTools(画图工具)    
string typeName;
CodeProject - DrawTools(画图工具)    
object drawObject;
CodeProject - DrawTools(画图工具)
CodeProject - DrawTools(画图工具)    
for ( int i = 0; i < n; i++ )
CodeProject - DrawTools(画图工具)    
{
CodeProject - DrawTools(画图工具)        
// object type
CodeProject - DrawTools(画图工具)
        typeName = info.GetString(
CodeProject - DrawTools(画图工具)            String.Format(CultureInfo.InvariantCulture,
CodeProject - DrawTools(画图工具)                
"{0}{1}",
CodeProject - DrawTools(画图工具)            entryType, i));
CodeProject - DrawTools(画图工具)
CodeProject - DrawTools(画图工具)        
// create object by type name using Reflection
CodeProject - DrawTools(画图工具)
        drawObject = Assembly.GetExecutingAssembly().CreateInstance(
CodeProject - DrawTools(画图工具)            typeName);
CodeProject - DrawTools(画图工具)
CodeProject - DrawTools(画图工具)        
// fill object from stream
CodeProject - DrawTools(画图工具)
        ((DrawObject)drawObject).LoadFromStream(info, i);
CodeProject - DrawTools(画图工具)
CodeProject - DrawTools(画图工具)        graphicsList.Add(drawObject);
CodeProject - DrawTools(画图工具)    }

CodeProject - DrawTools(画图工具)
CodeProject - DrawTools(画图工具)}

CodeProject - DrawTools(画图工具)

你可能感兴趣的:(project)