안녕하세요? 맨날맑음 입니다.

몇몇 프로그램을 보면, 윈도우끼리 도킹 기능으로 서로 일정거리 만큼 가까워지면 딱 달라붙게 만들어진 것을 볼 수 있습니다. 이런 기능의 명칭을 정확히 몰라서; 일단 제목은 '자석 윈도우'라고 정해 보았는데요;

밑의 예(이스트소프트의 알송)에서 볼 수 있듯이 각 윈도우끼리는 가까이 가면 달라 붙고, 제일 위의 윈도우를 이동하면 붙어있는 윈도우도 따라서 이동하게 됩니다.
이런 기능을 간단하게 Windows Form을 이용하여 만드는 방법을 알아보려 합니다. 이런 기능을 제공하는 Class Library가 있을까 찾아 보다가 결국 찾지는 못하고, 한 외국 사이트에 이와같은 소스를 발견하였습니다. 현재 출처를 정확하게 기억 나지 않습니다. 그래서 완성된 소스는 올리지 않습니다.(필요하신분은 요청하세요)
Form1.cs
 private void Form1_Move(object sender, EventArgs e)
        {
            if (isForm2Docked)
            {
                tempForm2.SetDesktopLocation(tempForm2.Location.X + (this.Location.X - prevLoc.X),
                    tempForm2.Location.Y + (this.Location.Y - prevLoc.Y));
            }
            prevLoc.X = this.Location.X;
            prevLoc.Y = this.Location.Y;
        }
 
메인이 되는 폼의 Move 이벤트에서는 현재 서브폼이 붙어있는지 확인하여, 붙어있으면 위치를 함께 옮겨줍니다.

Form2.cs
private void Form2_Move(object sender, EventArgs e)
        {
            bool amIDocked = false;
            Point newPoint = GetNewFormPosition(this, passedInForm, out amIDocked);
            this.SetDesktopLocation(newPoint.X, newPoint.Y);
            ((Form1)passedInForm).isForm2Docked = amIDocked;
        }

        public Point GetNewFormPosition(Form thisForm, Form parentForm, out bool isDocked)
        {
            int[] xRange = new int[2] { parentForm.Location.X, parentForm.Location.X + parentForm.Width };
            int[] yRange = new int[2] { parentForm.Location.Y, parentForm.Location.Y + parentForm.Height };
            int xGap = Math.Abs(thisForm.Location.X - parentForm.Location.X);
            int yGap = Math.Abs(thisForm.Location.Y - parentForm.Location.Y);
            int leftGap = Math.Abs((thisForm.Location.X + thisForm.Width) - parentForm.Location.X);
            int rightGap = Math.Abs(thisForm.Location.X - (parentForm.Location.X + parentForm.Width));
            int topGap = Math.Abs((thisForm.Location.Y + thisForm.Height) - parentForm.Location.Y);
            int bottomGap = Math.Abs(thisForm.Location.Y - (parentForm.Location.Y + parentForm.Height));
            int xNew = thisForm.Location.X;
            int yNew = thisForm.Location.Y;
            isDocked = false;

            if ((leftGap <= dockGap) && (((thisForm.Location.Y >= yRange[0]) && (thisForm.Location.Y <= yRange[1])) ||
                ((thisForm.Location.Y + parentForm.Height >= yRange[0]) && (thisForm.Location.Y + parentForm.Height <= yRange[1]))))
            {
                xNew = parentForm.Location.X - thisForm.Width;
                if (yGap <= dockGap) yNew = parentForm.Location.Y;
                isDocked = true;
            }
            if ((rightGap <= dockGap) && (((thisForm.Location.Y >= yRange[0]) && (thisForm.Location.Y <= yRange[1])) ||
                ((thisForm.Location.Y + parentForm.Height >= yRange[0]) && (thisForm.Location.Y + parentForm.Height <= yRange[1]))))
            {
                xNew = parentForm.Location.X + parentForm.Width;
                if (yGap <= dockGap) yNew = parentForm.Location.Y;
                isDocked = true;
            }
            if ((topGap <= dockGap) && (((thisForm.Location.X >= xRange[0]) && (thisForm.Location.X <= xRange[1])) ||
                ((thisForm.Location.X + parentForm.Width >= xRange[0]) && (thisForm.Location.X + parentForm.Width <= xRange[1]))))
            {
                yNew = parentForm.Location.Y - thisForm.Height;
                if (xGap <= dockGap) xNew = parentForm.Location.X;
                isDocked = true;
            }
            if ((bottomGap <= dockGap) && (((thisForm.Location.X >= xRange[0]) && (thisForm.Location.X <= xRange[1])) ||
                ((thisForm.Location.X + parentForm.Width >= xRange[0]) && (thisForm.Location.X + parentForm.Width <= xRange[1]))))
            {
                yNew = parentForm.Location.Y + parentForm.Height;
                if (xGap <= dockGap) xNew = parentForm.Location.X;
                isDocked = true;
            }
            return new Point(xNew, yNew);
        }

서브폼에서 좀 복잡해 보이긴 하지만, 메인폼의 영역을 알아와, 현재 서브폼의 위치가 달라 붙어야하는 위치라면 붙여 주고, 메인폼에 그 사실을 알리는 역할을 합니다.
이 소스를 응용하면, 상용프로그램처럼 윈도우간 도킹 기능을 만드는 것도 어렵지 않을 것 같습니다.

ps. 좌표를 일일이 비교해가며 구현하는 방법 외에 Class Library나 다른 방법을 아시는 분은 꼭 피드백을 부탁 드립니다!!
Posted by 맨날맑음

댓글을 달아 주세요

  1. 2009.08.14 13:45  댓글주소  수정/삭제  댓글쓰기

    비밀댓글입니다

  2. 윤우영 2009.10.25 13:15  댓글주소  수정/삭제  댓글쓰기

    소스좀 보내주세요...baegopa_2002@yahoo.co.kr
    좋은정보 감사드립니다.

  3. 레몬소다 2009.10.28 16:32  댓글주소  수정/삭제  댓글쓰기

    훈스에서 보고 블로그로 방문했어요 ^^
    예제 부탁드려요 ~
    ddobaggi@nate.com

  4. 마을 2009.12.04 22:20  댓글주소  수정/삭제  댓글쓰기

    좋은글이 많아서 좋은공부 했습니다.
    저도 소스좀 부탁 드리겠습니다.
    감사합니다.
    sorimael@gmail.com

  5. Benjamin 2010.01.07 16:46  댓글주소  수정/삭제  댓글쓰기

    상당히 좋은글을 많이 작성해 놓으셨네요~^^
    수고하셨습니다.^^
    저도 소스좀 보고 싶은데 부탁드리겠습니다.
    adsllsj@nate.com 그럼 좋은하루 되세요~^^

  6. soso 2010.06.19 21:42  댓글주소  수정/삭제  댓글쓰기

    안녕하세여 좋은 자료 잘 봤습니다
    소스좀 보고싶은데 보내주실수있을까요??
    늦었지만 ㅠ
    jjolyji@gmail.com 입니당
    수고하세요~!

  7. 김성천 2011.04.21 16:08  댓글주소  수정/삭제  댓글쓰기

    늦게 시작한 공부라서 여기저기 찾아다녀서 공부하고 있는 초짜입니다.
    참 좋은 자료 만드셨네요.
    공부 더욱 열공해야 겠다는 생각입니다.
    sckim7717@nate.com
    소스 보내 주시면 감사하겠습니다.

  8. Favicon of http://8344.taxfreebicycler.com/lvus.php BlogIcon louis vuitton 2013.07.27 09:32  댓글주소  수정/삭제  댓글쓰기

    태양이 바다에 미광을 비추면,나는 너를 생각한다.

  9. Favicon of https://yk778899.tistory.com BlogIcon 글쓰는 나그네 2018.08.02 12:15 신고  댓글주소  수정/삭제  댓글쓰기

    안녕하세요,
    저도 소스를 참고하고 싶은데, 부탁드리겠습니다.
    jenkioo@naver.com