FormBorderStyle = None 인 폼은 기본적으로 크기 조절 및 이동이 불가능합니다.

해결해야 할 것은 3가지 입니다.

 

1. 마우스가 테두리에 위치하여 크기를 변경 가능

2. 마우스 이동에 따른 이벤트 추가 (혹은 WndProc에서 제어도 가능!)

3. 최대화 시 작업표시줄을 가리지 않게 수정 (타이틀이 없기에 크기가 더 커집니다.)

 

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

namespace MoveableForm
{
    public partial class Form1 : Form
    {
        private int titleHeight = 32;
        private int padding = 5;

        private int offsetX;
        private int offsetY;
        private bool isMoving;

        //테스트용 출력 값
        private Dictionary<int, string> positionDict = new Dictionary<int, string>()
        {
            {0, "pass" },
            //{1, "clientInner" },
            //{2, "moveable and changeSize" },
            {10, "left" },
            {11, "right" },
            {12, "top" },
            {15, "bottom" },
            {13, "topLeft" },
            {14, "topRight" },
            {16, "bottomLeft" },
            {17, "bottomRight" }
        };

        public Form1()
        {
            InitializeComponent();
        }

        private IntPtr GetMousePosition (Point point)
        {
            int x = point.X;
            int y = point.Y;

            int width = this.ClientRectangle.Width;
            int height = this.ClientRectangle.Height;

            bool innerWidth = padding <= x && x < width - padding;
            bool innerHeight = padding <= y && y < height - padding;

            bool isTop = y <= padding / 2; //타이틀쪽 살짝 보정
            bool isBottom = height - padding <= y;
            bool isLeft = x <= padding;
            bool isRight = width - padding <= x;

            if (isLeft && innerHeight)  return (IntPtr)10; //left
            if (isRight && innerHeight) return (IntPtr)11; //right
            if (isTop && innerWidth)    return (IntPtr)12; //top
            if (isBottom && innerWidth) return (IntPtr)15; //bottom

            if (isTop && isLeft)        return (IntPtr)13; //topLeft
            if (isTop && isRight)       return (IntPtr)14; //topRight
            if (isBottom && isLeft)     return (IntPtr)16; //bottomLeft
            if (isBottom && isRight)    return (IntPtr)17; //bottomRight

            //1 : 클라이언트 내부인 경우.
            //2 : 윈도우창 움직이거나 더블클릭이 가능.
            //return y <= titleHeight ? (IntPtr)2 : (IntPtr)1;

            return (IntPtr)0;
        }

        protected override void WndProc(ref Message m)
        {
            //https://learn.microsoft.com/ko-kr/windows/win32/inputdev/wm-nchittest
            //WM_NCHITTEST = 0x84
            if (m.Msg == 0x84)
            {
                Point point = new Point(m.LParam.ToInt32());
                point = PointToClient(point);
                
                m.Result = GetMousePosition(point);
                label3.Text = positionDict[(int)m.Result]; //테스트용 값입니다.
                return;
            }

            base.WndProc(ref m);
        }

        private void label1_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void panel_title_MouseDown(object sender, MouseEventArgs e)
        {
            if (this.WindowState == FormWindowState.Maximized)
            {
                return;
            }

            offsetX = Cursor.Position.X - Location.X;
            offsetY = Cursor.Position.Y - Location.Y;

            isMoving = true;
        }

        private void panel_title_MouseMove(object sender, MouseEventArgs e)
        {
            if (isMoving)
            {
                Location = new Point(Cursor.Position.X - offsetX, Cursor.Position.Y - offsetY);
            }
        }

        private void panel_title_MouseUp(object sender, MouseEventArgs e)
        {
            isMoving = false;
        }

        private void panel_title_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (this.WindowState == FormWindowState.Normal)
            {
                //화면 최대화 시 하단의 작업표시줄을 덮지 않도록 해줍니다.
                this.MaximumSize = new Size(Screen.FromControl(this).WorkingArea.Width,
                                            Screen.FromControl(this).WorkingArea.Height);

                this.WindowState = FormWindowState.Maximized;
            }
            else
            {
                this.WindowState = FormWindowState.Normal;
            }
        }
    }
}

 

+ Recent posts