天天看点

DrawTools(画图工具) From CodeProject

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

DrawTools(画图工具) From CodeProject

Introduction

DrawTools sample shows how to create a Windows Forms application for drawing graphic objects in a Windows client area using mouse and drawing tools. Drawing tools implemented in this sample are: Rectangle, Ellipse, Line, and Pencil. There are well-known techniques for creating such type of applications, like: interaction with mouse, flicker-free drawing, implementing of drawing and selection tools, objects selection, managing of objects Z-order etc. MFC developers may learn all this stuff from MFC sample DRAWCLI. DrawTools C# program reproduces some of DRAWCLI functionality and uses some design decisions from this sample.

介绍

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

DrawTools solution contains two projects: DrawTools Windows Forms application and DocToolkit Class Library. DrawTools implements specific application stuff, and DocToolkit contains some standard classes for file managing.

Main features of the DrawTools solution are described below.

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

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

DrawTools(画图工具) From CodeProject
  • DrawArea - user control which fills main application window client area. Contains instance of the GraphicsList class. Draws graphic objects, handles mouse input passing commands to GraphicsList.
  • GraphicsList - list of graphic objects. Contains ArrayList of graphic objects. Talks with each graphic object by generic way using DrawObject methods.
  • DrawObject - abstract base class for all graphic objects.
  • DrawRectangle - rectangle graphic object.
  • DrawEllipise - ellipse graphic object.
  • DrawLine - line graphic object.
  • DrawPolygon - polygon graphic object.
  • Tool - abstract base class for all drawing tools.
  • ToolPointer - pointer tool (neutral tool). Contains implementation for selection, moving, resizing of graphic objects.
  • ToolObject - abstract base class for all tools which create new graphic object.
  • ToolRectangle - rectangle tool.
  • ToolEllipse - ellipse tool.
  • ToolLine - line tool.
  • ToolPolygon - polygon tool.
  • DrawArea – 用来填充主程序在窗体上可用区域的用户控件。包括GraphicsList 类的实例。绘制图形对象, 处理鼠标输入,把(鼠标)命令传给GraphicsList。
  • GraphicsList – 图形对象的列表。包括图形对象的ArrayList。通过使用DrawObject类中的方法与其他图形对象通讯
  • DrawObject – 所有图形对象的抽象基类。
  • DrawRectangle – 矩形图形对象。
  • DrawEllipise – 椭圆形图形对象。
  • DrawLine – 直线图形对象。
  • DrawPolygon – 多边形图形对象。
  • Tool – 所有画图工具的抽象基类。
  • ToolPointer – 箭头工具 (中性工具)。包含选择,移动,改变图形对象大小的实现。
  • ToolObject – 所有工具的抽象基类,用来创建新的图形对象。ToolRectangle – 矩形工具。
  • ToolEllipse – 椭圆形工具。
  • ToolLine – 直线工具。
  • ToolPolygon – 多边形工具。

DocToolkit Library

DocToolkit Library contains set of classes which may be used for creation of document-centric Windows Forms applications. Instances of classes exported from the DocToolkit Library are kept in the main form of the DrawTools project and used for general file-related operations.

DocToolkit 类库

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

  • DocManager class: Makes file-related operations: open, new, save, updating of the form title, registering of file type for Windows Shell. Built using the article Creating Document-Centric Applications in Windows Forms by Chris Sells.
  • DragDropManager class: Allows to open files dropped from Windows Explorer in Windows Form application.
  • MruManager class: Manages Most Recently Used Files list.
  • PersistWindowState class: Allows to keep last window state in the Registry and restore it when form is loaded. Source: Saving and Restoring the Location, Size and Windows State of a .NET Form By Joel Matthias.
  • 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.

Handling of Windows controls state at application idle time

Every Windows Forms application has a number of controls like menu items, buttons, toolbar buttons etc. Depending on current situation and user commands, these controls may have different states: enabled/disabled, checked/unchecked, visible/invisible etc. Every user action may change this state. Setting of controls' state in every message handler may be error-prone. Instead of this, it is better to manage controls' state in some function which is called after every user action. MFC has the great

ON_UPDATE_COMMAND_UI

feature which allows to update toolbar buttons' state at application idle time. Such a feature may be implemented also in .NET programs.

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

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

ON_UPDATE_COMMAND_UI

它允许在应用程序的空闲时间更新工具栏按钮的状态。这个特性也可以在.NET程序中实现。

Consider the situation when user clicks the Rectangle toolbar button. This button should be checked, and previously active tool should be unchecked. Rectangle button message handler doesn't change form controls' state, it just keeps current selection in some variable. Idle message handler selects active tool and unselects inactive tool.

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

DrawTools(画图工具) From CodeProject

private   void  Form1_Load( object  sender, System.EventArgs e)

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

{

DrawTools(画图工具) From CodeProject

    // Submit to Idle event to set controls state at idle time

DrawTools(画图工具) From CodeProject

    Application.Idle += new EventHandler(Application_Idle);

DrawTools(画图工具) From CodeProject

}

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

private   void  Application_Idle( object  sender, EventArgs e)

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

{

DrawTools(画图工具) From CodeProject

    SetStateOfControls();

DrawTools(画图工具) From CodeProject

}

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

public   void  SetStateOfControls()

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

{

DrawTools(画图工具) From CodeProject

    // Select active tool

DrawTools(画图工具) From CodeProject

    tbPointer.Pushed = (drawArea.ActiveTool == DrawArea.DrawToolType.Pointer);

DrawTools(画图工具) From CodeProject

    tbRectangle.Pushed = (drawArea.ActiveTool == DrawArea.DrawToolType.Rectangle);

DrawTools(画图工具) From CodeProject

    tbEllipse.Pushed  = (drawArea.ActiveTool == DrawArea.DrawToolType.Ellipse);

DrawTools(画图工具) From CodeProject

    tbLine.Pushed = (drawArea.ActiveTool == DrawArea.DrawToolType.Line);

DrawTools(画图工具) From CodeProject

    tbPolygon.Pushed = (drawArea.ActiveTool == DrawArea.DrawToolType.Polygon);

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

    menuDrawPointer.Checked = 

DrawTools(画图工具) From CodeProject

                      (drawArea.ActiveTool == DrawArea.DrawToolType.Pointer);

DrawTools(画图工具) From CodeProject

    menuDrawRectangle.Checked = 

DrawTools(画图工具) From CodeProject

                      (drawArea.ActiveTool == DrawArea.DrawToolType.Rectangle);

DrawTools(画图工具) From CodeProject

    menuDrawEllipse.Checked = 

DrawTools(画图工具) From CodeProject

                      (drawArea.ActiveTool == DrawArea.DrawToolType.Ellipse);

DrawTools(画图工具) From CodeProject

    menuDrawLine.Checked = (drawArea.ActiveTool == DrawArea.DrawToolType.Line);

DrawTools(画图工具) From CodeProject

    menuDrawPolygon.Checked = 

DrawTools(画图工具) From CodeProject

                      (drawArea.ActiveTool == DrawArea.DrawToolType.Polygon);

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

    // 

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

}

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

//  Rectangle tool is selected

DrawTools(画图工具) From CodeProject

private   void  CommandRectangle()

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

{

DrawTools(画图工具) From CodeProject

     drawArea.ActiveTool = DrawArea.DrawToolType.Rectangle;

DrawTools(画图工具) From CodeProject

}

DrawTools(画图工具) From CodeProject

Hit Test

DrawObject

class has virtual

HitTest

function which detects whether point belongs to graphic object:

Hit Test

DrawObject

类有一个叫

HitTest

的虚拟函数,用来侦测是否Point属于图形对象。

DrawTools(画图工具) From CodeProject

public   virtual   int  HitTest(Point point)

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

{

DrawTools(画图工具) From CodeProject

    return -1;

DrawTools(画图工具) From CodeProject

}

DrawTools(画图工具) From CodeProject

Derived classes use virtual

PointInObject

to make hit test. This function is called from

HitTest

.

DrawRectangle

class implements this function by a simple way:

继承类使用虚拟的

PointInObject

来做点击测试。这个函数调用自

HitTest

DrawRectangle

类使用了一种简单的方法实现了这个函数:

DrawTools(画图工具) From CodeProject

protected   override   bool  PointInObject(Point point)

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

{

DrawTools(画图工具) From CodeProject

    return rectangle.Contains(point);

DrawTools(画图工具) From CodeProject

    // rectangle is class member of type Rectangle

DrawTools(画图工具) From CodeProject

}

DrawTools(画图工具) From CodeProject

DrawLine

implementation of this function is more complicated:

DrawLine

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

DrawTools(画图工具) From CodeProject

protected   override   bool  PointInObject(Point point)

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

{

DrawTools(画图工具) From CodeProject

    GraphicsPath areaPath;

DrawTools(画图工具) From CodeProject

    Pen areaPen;

DrawTools(画图工具) From CodeProject

    Region areaRegion;

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

    // Create path which contains wide line

DrawTools(画图工具) From CodeProject

    // for easy mouse selection

DrawTools(画图工具) From CodeProject

    AreaPath = new GraphicsPath();

DrawTools(画图工具) From CodeProject

    AreaPen = new Pen(Color.Black, 7);

DrawTools(画图工具) From CodeProject

    AreaPath.AddLine(startPoint.X, startPoint.Y, endPoint.X, endPoint.Y);

DrawTools(画图工具) From CodeProject

        // startPoint and EndPoint are class members of type Point

DrawTools(画图工具) From CodeProject

    AreaPath.Widen(AreaPen);

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

    // Create region from the path

DrawTools(画图工具) From CodeProject

    AreaRegion = new Region(AreaPath);

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

    return AreaRegion.IsVisible(point);

DrawTools(画图工具) From CodeProject

}

DrawTools(画图工具) From CodeProject

DrawPolygon

function works by the same way, but

AreaPath

contains all lines in the polygon.

DrawPolygon

函数使用了同样的方法,但是

AreaPath

包含了多边形的所有线。

Serialization

GraphicList

class implements

ISerializable

interface which allows to make binary serialization of the class object.

DrawObject

class has two virtual functions which are used for serialization:

序列化

GraphicList

类实现了

ISerializable

接口,这个接口用作类对象的二进制序列化。

DrawObject

类有两个虚函数用来做序列化。

DrawTools(画图工具) From CodeProject

public   virtual   void  SaveToStream(SerializationInfo info,  int  orderNumber)

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

{

DrawTools(画图工具) From CodeProject

    // 

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

}

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

public   virtual   void  LoadFromStream(SerializationInfo info,  int  orderNumber)

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

{

DrawTools(画图工具) From CodeProject

  // 

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

}

DrawTools(画图工具) From CodeProject

These functions are implemented in every derived class. Binary file has the following format:

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

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

This allows to write generic serialization code in the GraphicList class without knowing any details about serialized objects:

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

DrawTools(画图工具) From CodeProject

private   const   string  entryCount  =   " Count " ;

DrawTools(画图工具) From CodeProject

private   const   string  entryType  =   " Type " ;

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

//  Save list to stream

DrawTools(画图工具) From CodeProject

[SecurityPermissionAttribute(SecurityAction.Demand, 

DrawTools(画图工具) From CodeProject

                         SerializationFormatter = true )]

DrawTools(画图工具) From CodeProject

public   virtual   void  GetObjectData(SerializationInfo info, 

DrawTools(画图工具) From CodeProject

                                     StreamingContext context)

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

{

DrawTools(画图工具) From CodeProject

    // number of objects

DrawTools(画图工具) From CodeProject

    info.AddValue(entryCount, graphicsList.Count);

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

    int i = 0;

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

    foreach ( DrawObject o in graphicsList )

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

{

DrawTools(画图工具) From CodeProject

        // object type

DrawTools(画图工具) From CodeProject

        info.AddValue(

DrawTools(画图工具) From CodeProject

            String.Format(CultureInfo.InvariantCulture,

DrawTools(画图工具) From CodeProject

                "{0}{1}",

DrawTools(画图工具) From CodeProject

                entryType, i),

DrawTools(画图工具) From CodeProject

            o.GetType().FullName);

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

        // object itself

DrawTools(画图工具) From CodeProject

        o.SaveToStream(info, i);

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

        i++;

DrawTools(画图工具) From CodeProject

    }

DrawTools(画图工具) From CodeProject

}

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

//  Load from stream

DrawTools(画图工具) From CodeProject

protected  GraphicsList(SerializationInfo info, StreamingContext context)

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

{

DrawTools(画图工具) From CodeProject

    graphicsList = new ArrayList();

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

    // number of objects

DrawTools(画图工具) From CodeProject

    int n = info.GetInt32(entryCount);

DrawTools(画图工具) From CodeProject

    string typeName;

DrawTools(画图工具) From CodeProject

    object drawObject;

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

    for ( int i = 0; i < n; i++ )

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

{

DrawTools(画图工具) From CodeProject

        // object type

DrawTools(画图工具) From CodeProject

        typeName = info.GetString(

DrawTools(画图工具) From CodeProject

            String.Format(CultureInfo.InvariantCulture,

DrawTools(画图工具) From CodeProject

                "{0}{1}",

DrawTools(画图工具) From CodeProject

            entryType, i));

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

        // create object by type name using Reflection

DrawTools(画图工具) From CodeProject

        drawObject = Assembly.GetExecutingAssembly().CreateInstance(

DrawTools(画图工具) From CodeProject

            typeName);

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

        // fill object from stream

DrawTools(画图工具) From CodeProject

        ((DrawObject)drawObject).LoadFromStream(info, i);

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

        graphicsList.Add(drawObject);

DrawTools(画图工具) From CodeProject

    }

DrawTools(画图工具) From CodeProject
DrawTools(画图工具) From CodeProject

}

继续阅读