반응형

WANIGrid Control은 지금까지의 작업으로 Grid Control의 가장 기본적인 기능들을 구현해 보았다.

Grid Header의 컬럼(Column)과 컬럼(Column) 사이의 경계 부분을 마우스 좌측 버튼 클릭 후 좌/우로 이동하면서 컬럼의 폭을 조정할 수 있는 기능을 구현해 보기로 하자.

이 기능을 구현하기 위해서 필요한 기능들을 크게 나열해 보면

  • 마우스 이동 시에 WANIGrid의 Header 영역의 X좌표를 체크해서 컬럼과 컬럼 경계선 범위에 마우스가 위치할 경우 마우스 커서의 모양을 Cursors.VSplit 으로 변경
  • 마우스 커스가 Cursors.VSplit으로 변경 상태에서 마우스 좌측 버튼이 눌러졌을 때 컬럼(Column) 폭 변경이 시작됨을 설정
  • 마우스 커서의 모양이 Cursors.VSplit 으로 변경 후 마우스 좌측 버튼을 누른 상태에서 마우스 이동 후 좌측 버튼을 놓았을 때 마우스 X 좌표를 계산해서 컬럼(Column)의 Width 값을 재계산
  • 마우스 커서를 Cursors.Default 다시 설정

마우스를 WANIGrid Header 영역의 컬럼과 컬럼 경계선에 가져가면 아래의 그림과 같이 마우스 커서가 변경된다.

[그림 16-1] 마우스 커스 변경 모습

이렇게 변경된 상태에서 마우스 좌측 버튼을 눌러서 컬럼의 폭을 원하는 사이즈 만큼 늘리거나 줄이면 된다.

이러한 작업을 하기위해서 기존의 소스에 추가 및 변경/보완 해야 할 부분들을 살펴보자.

먼저 추가해야 할 변수들을 살펴보기로 하자.

    private bool vSpliteLineMouseDown = false;  //컬럼 경계선 상에서 마우스 좌측버튼이 눌러졌는지를 저장하기 위한 변수
    private int resizeCol = 0;  //사이즈 변경이 발생한 컬럼을 저장하기 위한 변수
    private Point lastMousePoint = new Point(0, 0); //마우스 좌측 버튼을 누른 상태에서 마지막 이동 Point를 저장하기 위한 변수

 

마우스 이동 시에 WANIGrid Header 영역의 컬럼과 컬럼 경계선에 마우스가 위치하는지 체크하는 로직을 추가한다.

마우스 좌측 버튼을 누른 상태에서는 선택한 컬럼과 컬럼 경계선 상에 수직선을 그려서 현재 선택된 컬럼의 끝 부분을 가리키게끔 하는 기능과 마우스 좌측 버튼이 눌러지지 않았을 때 이동하는 마우스의 X좌표를 체크해서 마우스 커서를 변경하는 부분으로 구분된다.

MouseMove 이벤트를 생성해서 아래의 코드를 추가한다.

    private void WANIGrid_MouseMove(object sender, MouseEventArgs e)
    {
        //vSpliteLineMouseDown이 true 이면 마우스 버튼이 눌러진 상태에서 이동 중인 상태임.
        if (vSpliteLineMouseDown)
        {
            if (Math.Abs(e.X - lastMousePoint.X) > 4) DrawVSpliteLine(new Point(e.X, e.Y));
            return;
        }
        //WANIGrid Header영역의 마우스 위치를 체크

        //컬럼과 컬럼 사이의 경계선에 위치하면 Cursors.VSplit로 변경하고 resizeCol을 확인한다.
        Cursor = Cursors.Default;
        if (grid.GridHeaderList.Count > 0 && e.Y < topHeaderHeight)
        {
            int colLine = leftHeaderWidth; //각 컬럼이 끝나는 지점의 X좌표를 저장하는 변수
            for (int i = firstVisibleCol; i <= lastVisibleCol; i++)
            {
                if (!grid.GridHeaderList[i].Visible) continue;
                colLine += grid.GridHeaderList[i].Width;
                //Header의 컬럼과 컬럼 간의 경계선 상에 마우스 포인트가 위치했을 경우
                if (e.X > colLine - 2 && e.X < colLine + 2)
                {
                    Cursor = Cursors.VSplit;
                    resizeCol = i;
                    break;
                }                    
            }
        }
    }

 

마우스 좌측 버튼을 눌렀을 경우 선택된 경계 영역에 수직선을 그리는 메소드인 DrawVSpliteLine를 작성한다.

컬럼 사이즈 변경을 위해 Header영역의 컬럼과 컬럼 경계선을 선택하고 마우스 좌측 버튼을 누른 상태에서 마우스를 좌/우로 이동할 때 표시되는 세로선을 그리는 메소드이다.

    private void DrawVSpliteLine(Point pos)
    {
        int allHeight = topHeaderHeight + allRowsHeight;
        Graphics g = Graphics.FromHwnd(this.Handle);
        Rectangle rc = new Rectangle(lastMousePoint.X - 1, 1, 2, allHeight - (firstVisibleRow * rowHeight));
        Invalidate(rc);
        g.DrawLine(new Pen(Color.Gray, 2), pos.X, 1, pos.X, allHeight - (firstVisibleRow * rowHeight));
        lastMousePoint = pos;
        g.Dispose();
    }

 

최종적으로 컬럼 폭을 조정하고 난 후에 마우스 버튼을 놓았을 때 발생하는 MouseUp 이벤트에 컬럼의 변경 폭 값을 계산해서 Header 정보에 저장하고 화면을 다시 그리는 작업 및 마우스 포인트 값을 설정하는 부분을 추가한다.

    private void WANIGrid_MouseUp(object sender, MouseEventArgs e)
    {
        //컬럼 사이즈 변경이 완료 되었을 경우 현재 컬럼의 Width 값을 다시 계산해서 저장한다.
        if (vSpliteLineMouseDown)
        {
            int width = e.X - mousePoint.X;
            grid.GridHeaderList[resizeCol].Width += width;
            Invalidate();

            mousePoint.X = 0;
            mousePoint.Y = 0;
        }
        //vSpliteLineMouseDown 값을 false, Cursor를 Cursors.Default로 설정
        vSpliteLineMouseDown = false;
        Cursor = Cursors.Default;
    }

 

기존의 WANIGrid_MouseDown 이벤트에 마우스 Y좌표가 topHeaderHeight보다 작을 경우에 Cursor값을 체크해서 Cursor.VSplit인 경우에 vSpliteLineMouseDown 값을 true 그렇지 않을 경우 false를 설정하는 로직을 추가한다.

    private void WANIGrid_MouseDown(object sender, MouseEventArgs e)
    {
        //마우스 우측 버튼 클릭 시 Context 메뉴 제공
        if (e.Button == MouseButtons.Right)
        {
            //WANIGrid Header 영역이 선택되어졌을 경우에는 메뉴 제공하지 않음.
            if (e.Y < grid.TopHeaderHeight) return;
            //마우스 우측 버튼이 클릭된 좌표 값을 얻어온다.
            Point p = new Point(e.X, e.Y);

            rightClickMenu.Show(this, p);
        }
        else if (e.Button == MouseButtons.Left)
        {
            //WANIGrid Top Header 영역을 마우스 좌측 버튼으로 클릭했을 때
            if (e.Y < topHeaderHeight)
            {
                //Cursor가 Cursors.VSplite로 변경되었을 경우 vSpliteLineMouseDown을 true로 변경
                if (Cursor == Cursors.VSplit)
                {
                    vSpliteLineMouseDown = true;
                }
                else
                {
                    vSpliteLineMouseDown = false;
                    MouseLeftButtonClickInTopHeadHeight(sender, e);
                    Invalidate();
                }
                //Header 영역에서 왼쪽 마우스 버튼이 눌려졌을 때 마우스 포인트 저장.
                mousePoint.X = e.X;
                mousePoint.Y = e.Y;
            } 
            else //WANIGrid의 Top Header 영역을 제외한 영역에서 마우스 좌측 버튼을 클릭했을 때
            {
                MouseLeftButtonClickInContents(sender, e);
                Invalidate();
            }                
        }
    }

 

그리고 MouseMouseLeftButtonClickInTopHeadHeight, MouseLeftButtonClickInContents 메소드 내부에 있었던 Invalidate()를 위의 소스에서 처럼 바깥으로 가져왔다.

mousePoint를 설정하는 부분도 MouseMouseLeftButtonClickInTopHeadHeight 메소드 내부에서 바깥으로 가져왔다.

 

WANIGrid Control의 사이즈가 변경 되었을 경우, 선택 셀(Cell) Rectangle 부분도 Clear할 수 있도록 처리했다.

WANIGrid_Resize, WANIGrid_SizeChanged, WANIGrid_ClientSizeChanged 메소드에 ActiveCell.Clear() 호출을 추가.

 

    private void WANIGrid_Resize(object sender, EventArgs e)
    {
        rc = new Rectangle(0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height);
        ActiveCell.Clear();
        InitializeScollBar();
        ReCalcScrollBars();
        Invalidate();
    }

 

    private void WANIGrid_SizeChanged(object sender, EventArgs e)
    {
        rc = new Rectangle(0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height);
        ActiveCell.Clear();
        InitializeScollBar();
        ReCalcScrollBars();
        Invalidate();
    }

    private void WANIGrid_ClientSizeChanged(object sender, EventArgs e)
    {
        rc = new Rectangle(0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height);
        ActiveCell.Clear();
        InitializeScollBar();
        ReCalcScrollBars();
        Invalidate();
    }

 

이렇게 해서 WANIGrid Control에 컬럼(Column)의 폭(Width)을 조정할 수 있는 기능까지 구현을 해보았다.

지금까지의 작업으로 이젠 제법 그럴싸한 Grid Control의 모습을 갖추기 시작한 것 같다. 앞으로 가야할 길이 멀긴 하지만 조급해하지 않고 하나씩 만들어 간다는 기분으로 진행할 예정이다.

 

지금까지의 과정을 보고 추가 개선 및 신규 개발이 필요한 항목이 있거나 직접 보완 및 개발한 독자가 있다면 해당 소스를 같이 공유해 주길 바란다.

서로의 생각과 경험으로 지금 보다 나은 WANIGrid Control이 될 것이라 믿기에....주저하지 말고 의견 및 소스를 같이 공유하는 양방향 소통이 이루어지길 기원해 본다.

 

지금까지의 소스는 아래의 파일을 참조하기 바란다.

WANI Grid_20190813.zip
0.38MB

반응형

+ Recent posts