在上一篇  介紹完  可改變大小的直線後,這篇是進階版

上一篇有個問題 不能直接移動直線,但 直線不是我的重點,有興趣的人可以參考這篇的移動

 

 

首先一樣會用到上一篇可移動的方框,這是有4個,在圓的上下左右

這次可以自己畫圓,而且可以畫多個圓,所以需要一個 List 來存圓

 

簡單演算法

一個圓

圓的上下左右有個方框可以選擇

直接點圓,判別是哪個圓

點在圓上,可拖曳

拖曳  重新繪圖

點選方框,判別是哪個圓裡的方框

點選方框,可放大縮小

 

 

一樣,要用到 GraphicPath

首先   建立一個 圓的Class

(方框的 class 請參考上一篇   Bitmap 進階繪圖(一) )

/// <summary>
        /// 畫一個可移動的圓的結構
        /// </summary>
        public class Circle
        {
           public List<MovePoint> mp = new List<MovePoint>();         //圓四個可選取的框
           private Rectangle _rect;                                   //圓的大小
           private Point o;                                           //圓中心所在位置
           private int r = 5;                                       //圓的半徑
           private int l = 100;                                       //紀錄圓的直徑
           private int dx, dy;                                        //圓移動時的偏移值

           private bool flagDraw=false;
           public bool Select=false;
           public int mpIndex=0;
           private GraphicsPath gp ;                                  //傳回圓的 路徑
           private Pen pen = new Pen(Color.Blue, 1);                  //畫此圓的畫筆與顏色
           
            /// <summary>
            /// 新建一個圓
            /// </summary>
            /// <param name="e"></param>
            public Circle(Point e){
                O = e;
                Rect = new Rectangle(e.X - r/2 , e.Y -r/2 , r, r );
                                
                MovePoint mmp = new MovePoint(new Point (e.X , e.Y-r/2));
                mp.Add(mmp);
                mmp = new MovePoint(new Point(e.X-r/2, e.Y ));
                mp.Add(mmp);
                mmp = new MovePoint(new Point(e.X + r/2,e.Y  ));
                mp.Add(mmp);
                mmp = new MovePoint(new Point(e.X ,e.Y+r/2));
                mp.Add(mmp);
            }
            
            //----------------------------------------------------------------------------------------------
            /// <summary>
            /// 取得此圓的 畫框
            /// </summary>
            public  Rectangle Rect{
                get{return this._rect;}
                private set{ this._rect = value;}
            }
        
            //----------------------------------------------------------------------------------------------


            //by Rhine
            /// <summary>
            /// 取得 設定畫筆
            /// </summary>
            public Pen DrawPan
            {
                get { return pen; }
                set { pen = value; }
            }

            //----------------------------------------------------------------------------------------------
            /// <summary>
            /// 此圓的中心點
            /// </summary>
            public Point O{
                get { return this.o; }
                private set { this.o = value;}
            }
            //----------------------------------------------------------------------------------------------
            /// <summary>
            /// 是否可以移動  變大小
            /// </summary>
            public bool FlagDraw{
                get { return this.flagDraw;}
                set { this.flagDraw = value;}
            }
            //----------------------------------------------------------------------------------------------

            //by Rhine
            /// <summary>
            /// 得到變動後的 圓的 GraphicPath
            /// </summary>
            public GraphicsPath graphicPath
            {
                get { return this.gp; }
                private set { }
            }
            //----------------------------------------------------------------------------------------------
            /// <summary>
            /// 裡面的方框是否被選到
            /// </summary>
            /// <param name="e"></param>
            /// <returns></returns>
            public bool mpSelect(Point e)
            {
                for (byte i = 0; i < 4; i++)
                {
                    if (mp[i].CheckSelect(e))
                       return true;                  
                }
                return false;
            }
            //----------------------------------------------------------------------------------------------
            //by Rhine

            /// <summary>
            /// 判別是否選到此圓
            /// </summary>
            /// <param name="e"></param>
            /// <returns></returns>
            public bool CircleSelect(Point e)
            {
                if (Rect.Contains(e))
                {  //如果有選到圓,記錄點選的位置與圓中心的參數
                    dx = e.X - O.X ;
                    dy = e.Y - O.Y;
                    return true;
                }
                else
                    return false;
            }



            //----------------------------------------------------------------------------------------------
            /// <summary>
            /// 放大 縮小 繪圖
            /// </summary>
            /// <param name="e"></param>
            /// <returns></returns>
            public GraphicsPath draw(Point e)
            {
               l = (LineDist(O, e)) * 2;
               Rect = new Rectangle(O.X - l / 2, O.Y - l / 2, l, l);
               mp[0].move(new Point(O.X, O.Y - l / 2));
               mp[1].move(new Point(O.X - l / 2, O.Y));
               mp[2].move(new Point(O.X + l / 2, O.Y));
               mp[3].move(new Point(O.X, O.Y + l / 2));

               Rectangle ce = new Rectangle(O.X - 2, O.Y - 2, 4, 4);     //在中心的位置加入個小圓


                gp = new GraphicsPath() ;
                gp.AddEllipse(ce);
                gp.AddEllipse(Rect);
                gp.AddRectangle(mp[0].rect);
                gp.AddRectangle(mp[1].rect);
                gp.AddRectangle(mp[2].rect);
                gp.AddRectangle(mp[3].rect);
                return gp;
            }

            //----------------------------------------------------------------------------------------------
            //by Rhine

            //當移動圓 時用
            public GraphicsPath Move(Point e)
            {
               
                O = new Point((e.X - dx), (e.Y - dy));

                Rect = new Rectangle(O.X - l / 2, O.Y - l / 2, l, l);
                mp[0].move(new Point(O.X, O.Y - l / 2));
                mp[1].move(new Point(O.X - l / 2, O.Y));
                mp[2].move(new Point(O.X + l / 2, O.Y));
                mp[3].move(new Point(O.X, O.Y + l / 2));

                
                Rectangle ce = new Rectangle(O.X - 2, O.Y - 2, 4, 4);   //在中心的位置加入個小圓

                gp.Reset();
                gp.AddEllipse(Rect);
                gp.AddEllipse(ce);
                gp.AddRectangle(mp[0].rect);
                gp.AddRectangle(mp[1].rect);
                gp.AddRectangle(mp[2].rect);
                gp.AddRectangle(mp[3].rect);
                
                return gp;
            }

            /// <summary>
            /// 計算兩點距離
            /// </summary>
            /// <param name="p1"></param>
            /// <param name="p2"></param>
            /// <returns></returns>
            public static int LineDist(Point p1, Point p2)
            {

                return (int)Math.Sqrt(Math.Pow((p1.X - p2.X), 2) + Math.Pow((p1.Y - p2.Y), 2));
            }

         }

 

 

設定好後  一樣開啟一個 From 裡面放一個  Picturebox 與一個  buttom

一樣,需要在 Picturebox 上設定  Mouse_up Mouse_down and Mouse_Move 事件

     public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
        }

        [SerializableAttribute]
        public enum GCCollectionMode { };



        Bitmap bm;
        Graphics g;
        GraphicsPath gp;
        List<Circle> cir = new List<Circle>();

        bool drawCircle = false;                            //是否可以畫圓
        bool drawPic = false;                               //是否重新繪圖
        bool drawMove = false;                              //是否可移動

        int cir_index = -1;                                 //記錄目前所選取的圓
        //---------------------------------------------------------------------------------------------------

        private void Form2_Load(object sender, EventArgs e)
        {
            bm = new Bitmap(pictureBox1.Width, pictureBox1.Height);
          
            g = Graphics.FromImage(bm);
            gp = new GraphicsPath();
        }
        //---------------------------------------------------------------------------------------------------
        /// <summary>
        /// 新增一個圓用
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            if (drawCircle)
                drawCircle = false;
            else
                drawCircle = true;
        }
        //---------------------------------------------------------------------------------------------------
        /// <summary>
        /// 滑鼠點  下
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            if (drawCircle)
            {
                drawPic = true;
                cir_index = cir.Count;
                CDraw.Circle c = new CDraw.Circle(e.Location);
                cir.Add(c);

                gp.AddEllipse(cir[cir_index].Rect);

                g.DrawPath(new Pen(Color.Lime), gp);
                pictureBox1.BackgroundImage = bm;
            }
            else
            {
                if (cir.Count > 0)
                {
                    for (int i = 0; i < cir.Count; i++)
                    {
                        if (cir[i].mpSelect(e.Location))       //先看是否選到第i個圓的小框
                        {
                            cir_index = i;
                            drawPic = true;
                            drawCircle = true;
                            break;
                        }

                        if (cir[i].CircleSelect(e.Location)) //看是否選到圓
                        {
                            cir_index = i;
                            drawMove = true;
                            drawCircle = true;
                            cir[cir_index].FlagDraw = true;
                            break;
                        }
                    }
                }
            }
        }



            //by Rhine

        /// <summary>
        /// 滑鼠  上
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
        {
            if (cir.Count > 0)
            {
                cir[cir_index].FlagDraw = false;
                drawPic = false;
                drawCircle = false;
                drawMove = false;
            }

        }

        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            if (drawCircle) //是否要畫圓
            {

                bm = new Bitmap(pictureBox1.Width, pictureBox1.Height);

                g = Graphics.FromImage(bm);

                if (drawPic)   //是否伸縮 畫圓
                { cir[cir_index].draw(e.Location); }

                if (drawMove)  //是否移動畫圓
                { cir[cir_index].Move(e.Location); }

                for (int i = 0; i < cir.Count; i++)
                {
                    g.DrawPath(cir[i].DrawPan, cir[i].graphicPath);   //把每個圓的軌跡 畫出
                }
                pictureBox1.BackgroundImage = bm;
            }
        }


    }

 

成果

先畫兩個圓

Circle1.JPG

左邊的往下移動    右邊的放大

circle2.JPG

 

 

 

希望不會寫的太複雜,後面應該會再加幾個功能

比如 有選擇才顯示  小框

可改變顏色. 是否弄個Stack 來做移到最上層..等等

不過那也要等有空再來弄了

 

ps. 因為自己在用是包成將圓 與 小框另外包出 Class ,有出問題請檢察一下  NameSapce

 

arrow
arrow
    全站熱搜

    Rh 發表在 痞客邦 留言(5) 人氣()