퇴근5분전


전에 SBS 자막 프로젝트 할때...

당시 그쪽 인력들은 죄다 그래픽 관련인지라 더군다나 C++을 아주 아주 능숙하게 사용하는 사람들이었는데...

정말 잘 만들던데...

오늘 훈스에 별그리기, 그린 선을 클릭해서 이동하는 방법... 들에 대한 문의가 올라왔다.

그 동안 나도 공부도 했다 싶어서 도전...  별과 함게 딱 3시간 반,,, 별은 그닥 오래 안걸렸는데...

선 이동하는게 쉽지 않군... 그리는것 부터 해서 이동하는데 걸린 작업시간이 3시간. ( 뭐 나름 선방했다 치자.. )

 using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;

namespace makeClass
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            // 깜빡거릴것 같은....
            DoubleBuffered = true;
        }


        /// <summary>
        /// 자료구조( 점과 영역 저장)
        /// </summary>
        SortedList<string, PointList> Points = new SortedList<string, PointList>();
        protected override void OnPaint(PaintEventArgs e)
        {
            // 선택시 활성화
            if (_Selected)
            {
                e.Graphics.DrawRectangle(Pens.RoyalBlue, Rectangle.Truncate(Points[SelectKey].Region));
            }

            // 저장된 점 모두 그림.
            foreach (KeyValuePair<string, PointList > p1 in Points)
            {               
                for (int i = 0; i < p1.Value.Points.Count - 1; i++)
                {
                    e.Graphics.DrawLine(Pens.Red, p1.Value.Points[i], p1.Value.Points[i + 1]);
                }
            }          
            base.OnPaint(e);
        }

        //마우스 눌렸을때 ( 그리기 모드 )
        bool _MouseDown = false;
        //선택되었을때 ( 이동 모드 )
        bool _Selected = false;
        // 선택키
        string SelectKey = "";

        #region  그리기 & 이동에 필요한 변수
        PointF pt = new PointF();
        List<PointF> tmp = null;
        RectangleF rct; //= new Rectangle(0,0,0,0);        
        #endregion
        protected override void OnMouseDown(MouseEventArgs e)
        {      
            if (e.Button == MouseButtons.Left) // 그리기
            {
                rct = new RectangleF(0,0,0,0);
                pt =  rct.Location = e.Location;               
                tmp = new List<PointF>();
                tmp.Add(e.Location);
                _MouseDown = true;            
            }
            else if ( e.Button == MouseButtons.Right ) // 이동하기
            {
                pt = e.Location;
                foreach (KeyValuePair<string, PointList> kv in Points)
                {
                    _Selected = kv.Value.Region.Contains(e.Location);
                    if (_Selected)
                    {
                        SelectKey = kv.Key;
                        tmp = kv.Value.Points;
                        rct = kv.Value.Region;
                        break;
                    }
                }
            }
            base.OnMouseDown(e);
        }
      
        protected override void OnMouseMove(MouseEventArgs e)
        {
            if ( _MouseDown && tmp != null )
            {
                tmp.Add(e.Location);
                using (Graphics g = Graphics.FromHwnd(this.Handle))
                {
                    g.DrawLines(Pens.Red, tmp.ToArray() ); // 그리는걸 보여주기 위해..
                }
            }
            else if (_Selected && tmp != null)
            {
                tmp = Points[SelectKey].Points;
                PointF tm;
                // 포인트 스왑
                for (int idx = 0; idx < tmp.Count; idx++ )
                {
                    tm = tmp[idx];       
                    tm.X += e.Location.X - pt.X;
                    tm.Y += e.Location.Y - pt.Y;
                    tmp[idx] = tm;
                }
                // 영역 스왑
                rct = Points[SelectKey].Region;
                rct.X += e.Location.X - pt.X;
                rct.Y += e.Location.Y - pt.Y;
                Points[SelectKey].Region = rct;

                using (Graphics g = Graphics.FromHwnd(this.Handle))
                {
                    // 이동시 잔상 제거 및 다시 그리기.
                    Invalidate( Rectangle.Truncate( new RectangleF( rct.X - 100f, rct.Y - 100f, rct.Width + 200f, rct.Height + 200f )), true);              
                }
                pt = e.Location;
            }  
             //  base.OnMouseMove(e);
        }

        /// <summary>
        /// 자료구조 키값. ( 생성시... Object 구분값으로 씀)
        /// </summary>
        int PointKey = 0;
        protected override void OnMouseUp(MouseEventArgs e)
        {           
            if (tmp != null)
            {
                if (_MouseDown == true)
                {
                    tmp.Add(e.Location);                   
                    float maxX = 0;                   
                    float maxY = 0;

                    foreach (PointF pf in tmp)
                    {
                        if (rct.X > pf.X) rct.X = pf.X;
                        if (rct.Y > pf.Y) rct.Y = pf.Y;

                        if (maxX < pf.X) maxX = pf.X;
                        if (maxY < pf.Y) maxY = pf.Y;
                    }
                    rct.Width = maxX - rct.X;
                    rct.Height = maxY - rct.Y;
                    Points.Add((PointKey++).ToString(), new PointList(rct, tmp));
                }
                // 해제
                _Selected = false;
                _MouseDown = false;
                Invalidate();
                tmp = null;
            }
            base.OnMouseUp(e);
        }

       
       // 별그리기...
        private void DrawStar(Graphics g, double r,  PointF p)
        {
            PointF[] ps = new PointF[6];
            double RadianTheta = 0d;
            int cnt = 0;
            for (double i = 0; i <= 720d; i += 144d )
             {
                RadianTheta = i *  Math.PI / 180 ;
                 ps[  cnt ] = new PointF( p.X + (float)( r * 1d * Math.Cos( RadianTheta )) ,
                                                   p.Y +  (float)(  r * 1d * Math.Sin( RadianTheta ) ) );
                cnt ++;
            }
            g.DrawLines(Pens.Red, ps);
      
  }

      // 자료구조.
      public class PointList
        {
            public PointList(RectangleF rt, List<PointF> lp )
            {
                region = rt; points = lp;
            }

            RectangleF  region = new RectangleF();
            public RectangleF Region
            {
              get { return region; }
             set { region = value; }
            }

            List<PointF> points = new List<PointF>();
            public List<PointF> Points
            {
              get { return points; }
            set { points = value; }
            }
        }
    }
}

 


더블값 부호 후행 처리를 위해...

  string ss = "5000.00-";
            double d =  double.Parse(ss, System.Globalization.NumberStyles.AllowTrailingSign | System.Globalization.NumberStyles.Float);

SAP에서는 -가 뒤에 붙어오는데 이를 바꾸기 위해 위처럼. NumberStyles 값을 or해주면 된다.

SubComboBoxClass sb = new SubComboBoxClass();
sb.DataCode = "7001";
sb.Value = "V";

object obj = sb;
this.Text = string.Format("{0:KEY}", obj);

  위처럼 따로 정의한 객체가 특정 Format 형식을 지원하고자 할때 사용 할 수 있다.
가끔 다른 인터페이스랑 헷갈릴때가 있어서 기록해둔다.



internal class SubComboBoxClass : IFormattable
        {
            public string Name { get; set; }
            public string Value { get; set; }
            public string DataCode { get; set; }

            public override string ToString()
            {
                return ToString(null, null);
            }

            #region IFormattable 멤버

            public string ToString(string format, IFormatProvider formatProvider)
            {
                if (format == "KEY")
                {
                    return Value + DataCode;
                }

                return Name + ":" + DataCode + "[" + Value + "]";
            }

            #endregion
        }