在WinForm里绘图

    当我们需要使用Window的窗体进行绘图的时候可能会对绘制图的进行放大或缩小的操作,利用PictureBox控件默认是实现不了这个功能的,但是我们可以通过对一个一般的UserControl操作来达到这个目的,而不一定使用PictureBox,这里,我使用了Form或UserControl的基类ScrollableControl进行了继承并在其上绘图,因为这个控件足够使用了.

    我这里提到了如下的几个绘图的问题:

    1:当我们在Windows里绘图的时候所用的坐标系统和我们在数学里使用的坐标系是不一样的,我们需要对其进行转换以适合我们在数学坐标系里的习惯.

    2:当我们所需的画布大于当前窗口大小的时候需要滚动条的支持.

    3:我们可能随时对所绘的图进行放大或缩小.

    4:我们在绘图的时候不能出现闪动而使使用者感到讨厌,我们需要良好的显示效果,给人以快速的感觉

    5:我们可能需要绘制出数学函数图像.或是给了一堆的要绘图的坐标绘制出图像.

    如果您对上面的问题感兴趣,那么请参考下面的代码示例,如果对示例有问题也请指正以共同提高,谢谢!

定义绘图使用的控件:

 

///   <summary>
///  显示由Graphics绘制的图像
///   </summary>
internal   class  ImageBox : ScrollableControl
{
    
private  Color m_ColorCoordinate;
    
private  PointF[] m_Points;
    
private   float  m_Scale;
    
private  SizeF m_ImageSize;
    
///   <summary>
    
///  构造函数
    
///   </summary>
     public  ImageBox()
    {
        
this .SetStyle(ControlStyles.AllPaintingInWmPaint  |  ControlStyles.UserPaint  |  ControlStyles.OptimizedDoubleBuffer  |  ControlStyles.ResizeRedraw,  true );
        m_ColorCoordinate 
=  Color.Red;
        
this .m_Scale  =   1 ;
    }
    
///   <summary>
    
///  画布的大小
    
///   </summary>
     public  SizeF ImageSize
    {
        
get
        {
            
return  m_ImageSize;
        }
        
set
        {
            
this .m_ImageSize  =  value;
            
this .AutoScrollMinSize  =  Size.Ceiling( new  SizeF( this .m_ImageSize.Width  *   this .m_Scale,  this .m_ImageSize.Height  *   this .m_Scale));
        }
    }
    
///   <summary>
    
///  坐标系的X,Y两轴的颜色
    
///   </summary>
     public  Color ColorCoordinate
    {
        
get
        {
            
return   this .m_ColorCoordinate;
        }
        
set
        {
            
this .m_ColorCoordinate  =  value;
            
this .Invalidate( this .ClientRectangle,  false );
        }
    }
    
///   <summary>
    
///  重写以进行绘制
    
///   </summary>
    
///   <param name="e"></param>
     protected   override   void  OnPaint(PaintEventArgs e)
    {
        
base .OnPaint(e);
        
this .drawMathImage(e.Graphics,  this .getStartPoint(),  this .m_Scale);
    }
    
///   <summary>
    
///  得到Sin函数值坐标点
    
///   </summary>
    
///   <returns></returns>
     public   void  DrawSin()
    {
        List
< PointF >  list  =   new  List < PointF > ();
        
for  ( int  i  =   - 100   *  ( int )Math.PI; i  <   100   *  ( int )Math.PI; i ++ )
        {
            
float  x  =  i  /   100.0f ;
            
float  y  =  ( float )Math.Sin(( double )x);
            list.Add(
new  PointF(x  *   100 , y  *   100 ));
        }
        m_Points 
=  list.ToArray();
        
this .Invalidate();
    }
    
///   <summary>
    
///  得到抛物线函数值坐标点
    
///   </summary>
    
///   <returns></returns>
     public   void  DrawPow()
    {
        List
< PointF >  list  =   new  List < PointF > ();
        
for  ( int  i  =   - 100 ; i  <  ( int ) 100 ; i ++ )
        {
            
float  x  =  i  /  100f;
            
float  y  =  ( float )Math.Pow(( double )x,  2 );
            list.Add(
new  PointF(x  *   100 , y  *   100 ));
        }
        m_Points 
=  list.ToArray();
        
this .Invalidate();
    }
    
public   void  ClearFunImage()
    {
        
this .m_Points  =   null ;
        
this .Invalidate();
    }
    
///   <summary>
    
///  放大图像的倍数
    
///   </summary>
    
///   <param name="scale"></param>
     public   void  ScaleImage( float  scale)
    {
        
float  tmp  =  scale;
        
if  (tmp  >   0 )
        {
            
this .m_Scale  =  tmp;
            SizeF size 
=   new  SizeF( this .m_ImageSize.Width  *   this .m_Scale,  this .m_ImageSize.Height  *   this .m_Scale);

            
base .AutoScrollMinSize  =  Size.Ceiling(size);
            
this .Invalidate();
        }
    }
    
///   <summary>
    
///  由当前的滚动信息得到开始点以用来计算绘图原点信息
    
///   </summary>
    
///   <returns></returns>
     private  PointF getStartPoint()
    {
        SizeF size 
=   new  SizeF( this .m_ImageSize.Width  *   this .m_Scale,  this .m_ImageSize.Height  *   this .m_Scale);
        PointF point 
=   this .AutoScrollPosition;

        
if  (size.Width  >   this .ClientRectangle.Width  &&  size.Height  <   this .ClientRectangle.Height)
        {
            point.Y 
+=  ( this .ClientRectangle.Height  -  size.Height)  /   2.0f ;
        }
        
else   if  (size.Width  <   this .ClientRectangle.Width  &&  size.Height  >   this .ClientRectangle.Height)
        {
            point.X 
+=  ( this .ClientRectangle.Width  -  size.Width)  /   2.0f ;
        }
        
else   if  (size.Width  <=   this .ClientRectangle.Width  &&  size.Height  <=   this .ClientRectangle.Height)
        {
            point.Y 
+=  ( this .ClientRectangle.Height  -  size.Height)  /   2.0f ;
            point.X 
+=  ( this .ClientRectangle.Width  -  size.Width)  /   2.0f ;
        }
        
return  point;
    }
    
///   <summary>
    
///  使用指定的Graphics对象进行绘图
    
///   </summary>
    
///   <param name="g"> 用来绘图的Graphics对象 </param>
    
///   <param name="startPoint"> 绘图的时候坐标的偏移量 </param>
     private   void  drawMathImage(Graphics g, PointF start,  float  scale)
    {
        
// 建立坐标中点坐标
         float  tmpOX  =   this .AutoScrollMinSize.Width  /   2.0f ;
        
float  tmpOY  =   this .AutoScrollMinSize.Height  /   2.0f ;

        GraphicsState state 
=  g.Save();
        
using  (Matrix matrix  =   new  Matrix( 1 0 0 - 1 0 0 ))
        {
            g.Transform 
=  matrix;
            g.PageUnit 
=  GraphicsUnit.Pixel;
            g.TranslateTransform(tmpOX 
+  start.X,  - tmpOY  -  start.Y, MatrixOrder.Prepend);
            g.ScaleTransform(
this .m_Scale,  this .m_Scale, MatrixOrder.Prepend);

            
float  maxX  =  tmpOX  /  scale;
            
float  maxY  =  tmpOY  /  scale;

            
// 绘制坐标轴线
             using  (Pen pen  =   new  Pen( this .m_ColorCoordinate,  1 ))
            {
                g.DrawLine(pen, 
- maxX,  0.0f , maxX,  0.0f );
                g.DrawLine(pen, 
0.0f - maxY,  0.0f , maxY);

                g.DrawLine(pen, maxX, 
0.0f , maxX  -   2.0f 2.0f );
                g.DrawLine(pen, maxX, 
0.0f , maxX  -   2.0f - 2.0f );

                g.DrawLine(pen, 
0.0f , maxY,  2.0f , maxY  -   2.0f );
                g.DrawLine(pen, 
0.0f , maxY,  - 2.0f , maxY  -   2.0f );
            }
            
// 绘制函数图像
             if  (m_Points  !=   null   &&  m_Points.Length  >   1 )
            {
                g.DrawCurve(SystemPens.ControlText, m_Points);
            }
        }
        g.Restore(state);
    }
    
///   <summary>
    
///  重写以切换Sin,Pow函数图像进行绘图测试
    
///   </summary>
    
///   <param name="e"></param>
     protected   override   void  OnMouseDown(MouseEventArgs e)
    {
        
base .OnMouseDown(e);
        
if  (e.Button  ==  MouseButtons.Right)
        {
            
this .ClearFunImage();
            
return ;
        }
        
switch  (e.Clicks)
        {
            
case   1 :
                
this .DrawSin();
                
break ;
            
case   2 :
                
this .DrawPow();
                
break ;
        }
    }
    
protected   override   bool  ProcessDialogKey(Keys keyData)
    {
        
if  (keyData  ==  Keys.Add)
        {
            
this .ScaleImage( this .m_Scale  +   this .m_Scale  *   0.02f );
        }
        
else   if  (keyData  ==  Keys.Subtract)
        {
            
this .ScaleImage( this .m_Scale  -   this .m_Scale  *   0.02f );
        }
        
return   base .ProcessDialogKey(keyData);
    }
}

 

然后我们可以定义一个窗体用来承载这个控件以使控件展现它的行为:

 

public   class  testForm:Form
{
    
public  testForm()
    {
        
// InitializeComponent();

        ImageBox box 
=   new  ImageBox();
        box.Dock 
=  DockStyle.Fill;
        box.ImageSize 
=   new  Size( 200 150 );
        
this .Controls.Add(box);
    }
}

 

到这里我们可以运行testForm来通过点击使ImageBox显示出Sin函数或抛物线的数学图像.我们也可以通过键盘上的"+"及"-"来放大或缩小我们绘制的图,并在适当的时候通过滚动条来滚动显示图像.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值