어떤 분이 댓글로 도형과 도형을 클릭하면 직선으로 선이 이어지게 되는 것을 어떻게 구현하면 될지 질문해 주셨다.
그래서 도전해봤다.
컨셉으로 생각한 것은 다음과 같다.
PPT처럼 도형 위에 마우스를 가져가면 도형의 각 테두리 4개의 포인트가 표시가 되고,
마우스 클릭을 통해 두 개의 도형을 직선으로 이으면 될 것이라고 생각했다.
(이전 글에 이어서 구현했기 때문에, 아래 첨부된 코드에서 중략된 부분 및 전체 코드는 이전 글을 참고해 주세요.)
2020.10.16 - [IT] - [C#] 윈도우 그림판 기능 구현해보기 (PictureBox 그리기 기능, Undo/Redo 기능, 단축키 사용 방법)
[C#] 윈도우 그림판 기능 구현해보기 (PictureBox 그리기 기능, Undo/Redo 기능, 단축키 사용 방법)
그림판에 여러 기능들 중에서 크게 두 가지 기능을 구현해보겠습니다. 1. 도형(사각형, 원형, 선형직선) 그리기 기능과 2. 실행 취소(Undo)/다시 실행(Redo) 기능 두 가지 입니다. 그리고 흔히들 사용
ella-devblog.tistory.com
그림판 기능 미리보기
아래의 동영상을 통해 우리가 구현한 코드가 어떻게 동작하는지 확인해 보자.
(윈도우 자체 동영상 녹화 기능에서 콤보박스가 1도 안 나와서 어떻게 바꾸는지는 모르겠지만,,,
일단 동영상을 봐주시면 감사하겠습니다.)
![](https://blog.kakaocdn.net/dn/pb0eL/btq1vhnaEE5/6hvOjQC5BeJU80Nr3XCt71/img.png)
![](https://blog.kakaocdn.net/dn/cCnpWu/btq1yFN4agH/IeTIlBQNLRcGyjW7HHhcmK/img.png)
먼저, 마우스가 움직일 때 (MouseMove 이벤트) 마우스 위치에 있는 도형을 찾는 작업을 했다.
이전 글에서 도형(사각형, 원형 등)을 그릴 때 listRect에 저장하게 되어있었기 때문에,
마우스 위치를 확인해서 어떤 Rectangle 라인 위에 있는지 확인하고 listRect에서 몇 번째 도형인지 찾는다.
그러기 위해서 전역 변수로 위 사진과 같이 rectNum을 선언해서 사용했다.
(-1을 Default로 선언. 0은 array에서 사용하기 때문.)
FindRectangle 함수에서 rectNum을 찾고, 찾은 도형에 4개의 포인트를 표시하고 마우스 커서를 변경해주는 작업을 했다.
굳이 표시 안 하고, 마우스 커서도 그대로 쓰고 싶다면 rectNum만 찾고 다음 단계로 넘어가도 된다.
그리고, 직선 그리기 일 때만 도형과 도형을 잇기 위해서 toolType 이 DrawLine일 경우에만 도형을 찾게 했다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | private void pictureBox1_MouseMove(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { //...중략 } if (toolType == PaintTools.DrawLine) //마우스 위치에 있는 Rectangle 도형 파악하기 { //마우스 위치의 도형 리스트에서 찾기 rectNum = FindRectangle(listRect, new Point(e.X, e.Y)); if (rectNum != -1) { //도형 Edge 4개 포인트 표시 DrawEdgeRectangle(listRect[rectNum], listTool[rectNum]); //마우스 위치 확인하기 (도형 위에 있는지) UpdateMouseEdgeProperties(listRect[rectNum], new Point(e.X, e.Y)); //마우스 커서 변경하기 UpdateMouseCursor(pictureBox1); } else { pictureBox1.Refresh(); DrawBitmap(); } } else { //이 외의 경우 Default 값 -1로 표시 rectNum = -1; } } private int FindRectangle(List<Rectangle> r, Point e) { for (int i = 0; i < r.Count; i++) { if (e.X > (r[i].X - 7) && e.X < (r[i].X + r[i].Width + 7)) { if (e.Y > (r[i].Y - 7) && e.Y < (r[i].Y + r[i].Height + 7)) { //마우스가 i번째 도형 위에 위치함 return i; } } } //마우스가 어느 도형 위에도 위치하지 않음 return -1; } | cs |
각각의 함수는 주석을 참고해 주세요 : )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | //마우스 위치를 파악하기 위한 boolean 변수 public static bool MouseIsInLeftCenter { get; set; } public static bool MouseIsInRightCenter { get; set; } public static bool MouseIsInTopCenter { get; set; } public static bool MouseIsInBottomCenter { get; set; } private void DrawEdgeRectangle(Rectangle r, PaintTools t) { //마우스가 도형 위에 위치하는 경우 도형 4면 Edge에 표시 Pen pnP = new Pen(Color.Red); pnP.DashStyle = DashStyle.Solid; Graphics g = pictureBox1.CreateGraphics(); g.DrawRectangle(pnP, r.X - 2, r.Y - 2 + r.Height / 2, 4, 4); g.DrawRectangle(pnP, r.X - 2 + r.Width / 2, r.Y - 2, 4, 4); g.DrawRectangle(pnP, r.X - 2 + r.Width / 2, r.Y - 2 + r.Height, 4, 4); g.DrawRectangle(pnP, r.X - 2 + r.Width, r.Y - 2 + r.Height / 2, 4, 4); } private static void UpdateMouseEdgeProperties(Rectangle r, Point e) { //마우스가 도형 위의 어느 포인트에 위치하는지 파악 MouseIsInLeftCenter = (Math.Abs(e.X - r.X) <= 7) && (e.Y > r.Y) && (e.Y < r.Y + r.Height); MouseIsInRightCenter = (Math.Abs(e.X - r.X - r.Width) <= 7) && (e.Y > r.Y) && (e.Y < r.Y + r.Height); MouseIsInTopCenter = (Math.Abs(e.Y - r.Y) <= 7) && (e.X > r.X) && (e.X < r.X + r.Width); MouseIsInBottomCenter = (Math.Abs(e.Y - r.Y - r.Height) <= 7) && (e.X > r.X) && (e.X < r.X + r.Width); } private static void UpdateMouseCursor(Control control) { //만약 도형위에 마우스가 위치하면 마우스 커서를 십자가 모양으로 변경 if (MouseIsInLeftCenter || MouseIsInRightCenter || MouseIsInTopCenter || MouseIsInBottomCenter) { control.Cursor = Cursors.Cross; } else { control.Cursor = Cursors.Default; } } | cs |
그런 다음 도형과 도형을 직선으로 잇자.
먼저, MouseDown 이벤트에서 처음 선택한 도형의 포인트를 찾는다.
도형 위에서 클릭할 때만 처음 clickPoint를 변경하기 위해 rectNum이 -1이 아닐 때를 찾는다.
FindPoint에서 도형의 4개 포인트 중 현재 마우스 위치와 가장 가까운 포인트를 찾는다.
그리고 마우스를 다음 도형에서 떼는데, MouseUp 이벤트에서 처음 위치 찾듯이 마지막 도형 포인트를 찾는다.
그러면 위의 동영상과 같이 도형과 도형을 잇는 직선이 그려진다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | private void pictureBox1_MouseDown(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { //마우스 클릭 위치 저장 clickPoint = new Point(e.X, e.Y); first = true; //마우스 도형 클릭 시 도형 위 4개의 포인트로 clickPoint 변경 if (rectNum != -1) { clickPoint = FindPoint(listRect[rectNum], clickPoint); } } } private void pictureBox1_MouseUp(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { //...중략 if (toolType == PaintTools.DrawRectangle) { //...중략 } else if (toolType == PaintTools.DrawLine) //선형 그리기 { Point lastPoint = new Point(); //lastPoint도 clickPoint와 마찬가지로 도형 클릭 시 도형 위 4개의 포인트로 변경 if (rectNum != -1) { lastPoint = FindPoint(listRect[rectNum], new Point(e.X, e.Y)); rect = new Rectangle(clickPoint.X, clickPoint.Y, clickPoint.X + lastPoint.X, clickPoint.Y + lastPoint.Y); } else { rect = new Rectangle(clickPoint.X, clickPoint.Y, clickPoint.X + e.X, clickPoint.Y + e.Y); } } //...중략 } } private Point FindPoint(Rectangle r, Point e) { //마우스가 도형 위 4개 포인트에서 제일 가까운 도형 위 포인트 리턴 Point rectPoint = new Point(); rectPoint.X = Math.Abs(e.X - r.X) > Math.Abs(e.X - (r.X + r.Width / 2)) ? r.X + r.Width / 2 : r.X; if (Math.Abs(e.X - r.X) < Math.Abs(e.X - (r.X + r.Width / 2))) rectPoint.X = r.X; else if (Math.Abs(e.X - (r.X + r.Width / 2)) < Math.Abs(e.X - (r.X + r.Width))) rectPoint.X = r.X + r.Width / 2; else rectPoint.X = r.X + r.Width; if (Math.Abs(e.Y - r.Y) < Math.Abs(e.Y - (r.Y + r.Height / 2))) rectPoint.Y = r.Y; else if (Math.Abs(e.Y - (r.Y + r.Height / 2)) < Math.Abs(e.Y - (r.Y + r.Height))) rectPoint.Y = r.Y + r.Height / 2; else rectPoint.Y = r.Y + r.Height; return rectPoint; } | cs |
급하게 포스팅 올리느라 설명이 충분하지 않을 수 있습니다,,ㅎㅎ 궁금하신 점은 댓글로 마구 질문해주세요 : )
그럼 도움이 되셨다면 공감 꾹 눌러주시면 감사하겠습니다❣️
'IT > C#' 카테고리의 다른 글
[C#] 마우스 위치에 따라 3배 확대 이미지 보여주는 프로그램 (feat. 반투명 사각형 그리기) (0) | 2022.04.15 |
---|---|
[C#] 선택된 사각형 위에서 마우스커서 모양 변경하기 (0) | 2022.04.06 |
[C#] MySQL to SQLite Converter (0) | 2021.03.25 |
[C#] SQLite 설치 및 사용하기 (0) | 2021.03.15 |
[C#] MySql DB 연동하여 로그인 구현하기 (feat. 카카오톡 PC 버전 UI) (39) | 2020.12.04 |