太白将进酒,共邀天下友

形位合成变动静,有无陈新映全域。 内外移思抽精明,连续离散归终果。

导航

[导入]Netron研究(三)----"移动和联通"之移动篇

  • 序:    在这里,我可不是要讨论中国移动和中国联通谁的信号好,收费低,而是针对Netron中的两大重要操作:图形的移动和图形的联接进行分析.:)

  • 移动篇
    对于图形设计器来讲,图形的移动应该是其中非常核心的一部分.接下来,就来分析下Netron是怎么实现这个核心功能的.
    关于这点,要首先回顾下前面随笔提到的一些东西.Netron中所有的具体图形对象(椭圆,矩行...)都继承自ShapeBase这个基类,而ShapeBase又是继承自Entity这个抽象类的.下面,我们就先深入Entity内部,看看他的五脏六腹到底是怎么样的.Entity类的核心内容如下:
    public abstract class Entity {
    ...
    protected internal bool hovered = false; protected GraphControl site; protected bool isSelected = false;
    [Browsable(false)] public bool IsSelected { get{return isSelected;} set{isSelected = value;} } [Browsable(false)] public GraphControl Site { get{return site;} set{site = value;} } public abstract void Paint(Graphics g); public abstract bool Hit(Point p); public abstract void Invalidate(); public abstract void Move(Point p); }
     其中,hovered表示鼠标是否悬浮在图形上.site表示该图形所在的GraphControl(可以把他理解为一个图形设计器).isSelected表示这个图形是否被选中.这个抽象类包括四个抽象方法:
    Paint方法指定各种不同的图形元素应该怎么在窗体上画出他自身.
    Hit方法判断图形是否被鼠标点中.
    Invalidate方法使图形元素失效,由此产生OnPaint消息,进行窗体的刷新.
    Move方法是图形移动控制的方法.

    接下来,我们看看所有具体图形对象的直接父类ShapeBase(继承自Entity)中,关于图形移动的核心内容
    public class ShapeBase : Entity { ...... protected Rectangle rectangle; public int X { get{return rectangle.X;} set{ Point p = new Point(value - rectangle.X, rectangle.Y); this.Move(p); Site.Invalidate(); //note that 'this.Invalidate()' will not be enough } } public int Y { get{return rectangle.Y;} set{ Point p = new Point(rectangle.X, value - rectangle.Y); this.Move(p); Site.Invalidate(); } } public Point Location { get{return new Point(this.rectangle.X,this.rectangle.Y);} set{ //we use the move method but it requires the delta value, not an absolute position! Point p = new Point(value.X-rectangle.X,value.Y-rectangle.Y); //if you'd use this it would indeed move the shape but not the connector s of the shape //this.rectangle.X = value.X; this.rectangle.Y = value.Y; Invalidate(); this.Move(p); } } public override void Paint(System.Drawing.Graphics g) { return; } public override bool Hit(System.Drawing.Point p) { return false; } public override void Invalidate() { site.Invalidate(rectangle); } public override void Move(Point p) { this.rectangle.X += p.X; this.rectangle.Y += p.Y; for(int k=0;k<this.connectors.Count;k++) { connectors[k].Move(p); } this.Invalidate(); } ...... }
     其中rectangle是具体图形所在的矩型区域.
    X,Y,Location是该矩型所在的位置.
    ShapeBase类没有具体实现抽象类Entity中的抽象方法,Paint,Hit.因为这两个具体的操作应该交给具体的子类来实现.(比如,矩行图形和椭圆图形的Paint的具体实现就不相同.剩下的两个方法Invalidate和Move,这都是所有图形共用的方法,很简单吧?

    下面,我将用一个具体的图形元素:SimpleRectangle来说明下各个具体图形是怎么进行和移动有关的处理的.SimpleRectangle类的核心内容如下:
    public class SimpleRectangle : ShapeBase { public override bool Hit(System.Drawing.Point p) { Rectangle r= new Rectangle(p, new Size(5,5)); return rectangle.Contains(r); } public override void Paint(System.Drawing.Graphics g) { g.FillRectangle(shapeBrush,rectangle); if(hovered || isSelected) g.DrawRectangle(new Pen(Color.Red,2F),rectangle); else g.DrawRectangle(blackPen,rectangle); for(int k=0;k<connectors.Count;k++) { connectors[k].Paint(g); } //well, a lot should be said here like //the fact that one should measure the text before drawing it, //resize the width and height if the text if bigger than the rectangle, //alignment can be set and changes the drawing as well... //here we keep it really simple: if(text !=string.Empty) g.DrawString(text,font,Brushes.Black, rectangle.X+10,rectangle.Y+10); }

    public override void Invalidate() { Rectangle r = rectangle; r.Offset(-5,-5); r.Inflate(20,20); site.Invalidate(r); } }
     其中,Hit方法判断该矩行是否被鼠标点中,他通过定义一个Size为5,5的小矩行,该小矩型左上角的坐标是鼠标点击的点,看这个小矩行是否完全包含在图形矩行中.
    Paint方法是矩形图形将自身绘制出来的方法.其中有进行Connector和矩行中的文本的处理,在移动篇里暂时不对他们进行说明.不过也相当简单.
    Invalidate方法使该矩行失效,然后对窗体进行重新绘制.

    现在,各个图形子元素已经具有了移动的行为,接下来看一看图形设计器GraphControl类是怎么控制各个图形元素的移动的.GraphControl类控制图形移动的关键内容如下:
    首先,是在图形设计器上单击,响应单击事件的代码如下:
    protected override void OnMouseDown(MouseEventArgs e) { base.OnMouseDown (e); Point p = new Point(e.X,e.Y);
    ......
    //test for shapes for(int k=0; k<shapes.Count; k++) { if(shapes[k].Hit(p)) { //shapes[k].ShapeColor = Color.WhiteSmoke; tracking = true; if(selectedEntity!=null) selectedEntity.IsSelected=false; selectedEntity = shapes[k]; selectedEntity.IsSelected = true; refp=p; if(OnShowProps!=null) OnShowProps(this.shapes[k]); if(e.Button==MouseButtons.Right) { if(OnShowProps!=null) OnShowProps(this); } return; } } if(selectedEntity!=null) selectedEntity.IsSelected=false; selectedEntity = null; Invalidate(); refp = p; //useful for all kind of things //nothing was selected but we'll show the props of the control in this case if(OnShowProps!=null) OnShowProps(this.proxy); }
     首先得到鼠标点击的X,Y坐标,GraphControl中的shapes前一篇随笔提到过,是一个ShapeCollection对象,保存所有的图形元素.然后通过这个图形元素自身的Hit方法判断是否选中了某一个图形元素.如果选中了一个图形元素,则将tracking置为true(为移动做准备).并将该图形元素定了唯一的选中图形.接下来是显示该图形的属性(这不是本随笔的重点,暂不说明).

    确定了选中的图形元素后,在鼠标移动的时候,响应鼠标的OnMouseMove事件,如果tracking是true的话,则将唯一选中的图形元素进行移动(移动的实现是在各个图形元素中的).最后,在OnMouseUp时间中将tracking置为false,至此,完成了整个图形移动的任务.
    (发现代码贴得太多了,"联通篇"还是重起一篇随笔分析吧)

----2005.12.25 15:59 星期日


文章来源:http://www.agilelabs.cn/blogs/woody/archive/2005/12/25/310.aspx

posted on 2006-01-16 11:03  太白飞仙  阅读(1110)  评论(1编辑  收藏  举报