반응형

앞 시간에 Grid Header를 그렸고 이제는 가로 스크롤바에 대한 이벤트를 생성해보기로 하자.

Column이 많아지면 가로 스크롤바가 나타나고 스크롤 이벤트에 따라 컬럼들을 이동해서 보여주어야 한다.

이러한 작업을 하기 위해서 먼저 DefaultHeaderGenerator Class의 DrawHeaders 메소드를 살펴 보기로 하자.

이전 소스에서는 첫번째 컬럼부터 마지막 컬럼까지 Header를 보여주기 위한 목적으로 DrawHeaders 메소드를 간단하게 작성했었다.

이제는 화면에 보여져야 할 첫번째 컬럼과 마지막 컬럼을 기준으로 Grid Header정보를 그려야 한다.

이전 소스의 변경 부분은 아래와 같다.

[HeaderGenerator.cs]

Header의 첫번째 컬럼에서 마지막 컬럼까지의 폭이 Client 폭 보다 클 경우에 true, 그렇지 않을 경우에 false를 설정하기 위한 변수 선언

protected bool isLargeLastCol = false;    //첫번째 컬럼에서 마지막 컬럼 까지의 폭이 Client 폭 보다 클 경우 true

 

외부에서 get/set 할 수 있도록 Property 선언

public bool IsLargeLastCol
{
    get { return isLargeLastCol; }
    set { isLargeLastCol = value; }
}

 

[DefaultHeaderGenerator.cs]

public override void DrawHeaders(int firstVisibleCol, int lastVisibleCol, int controlWidth, Graphics graphics, Rectangle rect)
{
    SolidBrush brush = new SolidBrush(SystemColors.Control);
    Pen pen = new Pen(SystemColors.ControlLight);

    int columnStartX = 0;
    graphics.FillRectangle(brush, columnStartX + 1, 1, leftHeaderWidth, topHeaderHeight);
    graphics.DrawRectangle(pen, columnStartX + 1, 1, leftHeaderWidth, topHeaderHeight);

    for (int i = firstVisibleCol; i <= lastVisibleCol; i++)
    {
        if (i == firstVisibleCol) columnStartX += leftHeaderWidth;  //첫 시작컬럼의 폭을 leftHeaderWidth 만큼 설정
        int headerWidth = this._headers[i].Width;   //i 번째 컬럼의 폭을 설정

        //보여지는 컬럼의 폭이 컨트롤의 폭 보다 클경우
        if (columnStartX  + headerWidth > controlWidth)
        {
            headerWidth = controlWidth - columnStartX - 3;
            if (lastVisibleCol == _headers.Count - 1) IsLargeLastCol = true;
        } else
        {
            IsLargeLastCol = false;
        }

        //헤더영역의 사각형을 채우고 테두리를 그린다.
        graphics.FillRectangle(brush, columnStartX + 1, 1, headerWidth, topHeaderHeight);
        graphics.DrawRectangle(pen, columnStartX + 1, 1, headerWidth, topHeaderHeight);

        //헤더 타이틀 정렬 방법 설정
        StringFormat sf = new StringFormat();
        sf.LineAlignment = StringAlignment.Center;
        sf.Alignment = StringUtil.GetStringAlignment(sf, HorizontalAlignment.Center);

        //헤더 타이틀을 그린다.
        Rectangle colRec = new Rectangle(columnStartX + 1, 1, headerWidth, topHeaderHeight);
        graphics.DrawString(this._headers[i].Title, headerFont, blackBrush, colRec, sf);

         columnStartX += headerWidth;
    }
}

 

[WANIGrid.cs]

가로 스크롤바를 움직였을 때 동작하기 위한 변수를 추가로 선언한다.

private int allColsWidth = 0;   //Grid 컬럼 전체의 폭
private int lastHScrollValue = 0; //가로 스크롤바를 최대값까지 갔을 경우 보여지는 컬럼 수를 2로 나눈 값 - 스크롤 시 이동 거리를 말함
private bool chkLast = false; //마지막 컬럼의 폭을 지정했던 폭 만큼 보여졌을 때 true

 

생성자에 hScrollBar의 최소 변경 값을 설정한다.

public WANIGrid()
{            
    InitializeComponent();
    if (grid == null) grid = new WANI_Grid.Grid.Grid();             
    hScrollBar.SmallChange = 1;
}

 

이벤트 핸들러 초기화

public void EventHandlerInitialize()
{
    hScrollBar.Scroll += new ScrollEventHandler(HScrollBar_Scroll);
}

 

가로 스크롤바를 스크롤 했을 때 발생하는 이벤트

        public void HScrollBar_Scroll(object sender, ScrollEventArgs e)
        {
            //가로 스크롤바를 움직여서 마지막 컬럼이 Client 영역에 나타났을 때
            if (e.NewValue >= (grid.GridHeaderList.Count - lastHScrollValue))
            {
                //마지막 컬럼의 전체가 Client 영역에 모두 나타나지 않았을 때
                if (grid.HeaderGen.IsLargeLastCol)
                {
                    //마지막 컬럼을 1칸 앞으로 땡긴다.
                    if (grid.LastVisibleCol >= grid.GridHeaderList.Count - 1)
                    {
                        if (!chkLast)
                        {
                            firstVisibleCol += 1;
                            grid.FirstVisibleCol = firstVisibleCol;
                            e.NewValue = firstVisibleCol;
                            chkLast = true;
                        }
                    }
                }
                else
                {
                    if (e.NewValue <= grid.GridHeaderList.Count - lastHScrollValue)
                    {
                        firstVisibleCol = e.NewValue;
                        grid.FirstVisibleCol = firstVisibleCol;
                        chkLast = false;
                    }
                }
            }
            else
            {
                if (e.NewValue < (grid.GridHeaderList.Count - lastHScrollValue))
                {
                    if (firstVisibleCol < grid.LastVisibleCol)
                    {
                        firstVisibleCol = e.NewValue;
                        grid.FirstVisibleCol = firstVisibleCol;
                        chkLast = false;
                    }
                }
            }
            CalcVisibleRange();
            ReCalcScrollBars();
            Invalidate();
        }

 

가로/세로 스크롤바를 재계산 하는 메소드. 세로 스크롤바 재계산 로직은 추후에 추가될 것이다.

        private void ReCalcScrollBars()
        {
            if (hScrollBar == null || vScrollBar == null) return;

            if (grid != null && grid.GridHeaderList != null) 

                allColsWidth = grid.GridHeaderList[grid.GridHeaderList.Count() - 1].Left + grid.GridHeaderList[grid.GridHeaderList.Count() - 1].Width;

 

            //컬럼의 폭이 클라이언트 사이즈 폭 보다 클 경우 가로 스크롤바를 보여준다.
            if ((allColsWidth > 0) && (allColsWidth > ClientSize.Width - ysclWidth))
            {
                hScrollBar.Visible = true;
                hScrollBar.LargeChange = ((lastVisibleCol - firstVisibleCol) + 1) / 2 + 1;
                lastHScrollValue = ((lastVisibleCol - firstVisibleCol) + 1) / 2 + 1;
            }
            else
            {
                hScrollBar.Visible = false;
                grid.FirstVisibleCol = 0; //Control 크기가 바뀌면서 hScrollBar가 가려지면 Grid의 첫번째 컬럼 부터 그려지도록 처리
            }
        }

 

WANIGrid Control Load 시에 스크롤바의 이벤트 핸들러를 초기화 한다.

        private void WANIGrid_Load(object sender, EventArgs e)
        {
            //더블버퍼링(Double Buffering) 처리
            this.SetStyle(ControlStyles.DoubleBuffer, true);
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.UserPaint, true);

            rc = new Rectangle(0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height);
            EventHandlerInitialize(); //스크롤 이벤트 초기화
            InitializeScollBar();
            Invalidate();
        }

 

WANIGrid Control Resize 이벤트 시에 ReCalcScrollBars 추가 한다.

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

 

WANIGrid Control Paint 이벤트 시에 ReCalcScrollBars 추가 한다.
        private void WANIGrid_Paint(object sender, PaintEventArgs e)
        {
            CalcVisibleRange();
            ReCalcScrollBars();
            DrawBackground(e.Graphics, rc);
            DrawHeaders(e.Graphics, rc);
        }

 

WANIGrid Control SizeChanged 이벤트 시에 ReCalcScrollBars 추가 한다.
        private void WANIGrid_SizeChanged(object sender, EventArgs e)
        {
            InitializeScollBar();
            ReCalcScrollBars();
            Invalidate();
        }

 

WANIGrid Control ClientSizeChanged 이벤트 시에 ReCalcScrollBars 추가 한다.
        private void WANIGrid_ClientSizeChanged(object sender, EventArgs e)
        {
            rc = new Rectangle(0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height);
            InitializeScollBar();
            ReCalcScrollBars();
            Invalidate();
        }

 

이렇게 소스를 변경하고 실행하면 스크롤바를 움직일때 마다 컬럼이 바뀌어짐을 알 수 있다.

[그림 7-1] 실행 첫 화면
[그림 7-2] 스크롤 이벤트 발생 시 변경된 화면

이렇게 해서 WANIGrid Control의 가로 스크롤 이벤트 발생 시 Grid Header의 컬럼 정보를 볼 수 있도록 했다.

행이 추가 되기 전 전체 컬럼을 모두 살펴볼 수 있는 기능을 개발한 것이며, 오늘 까지 이렇게 만든 기능들은 추후 계속해서 변화 또는 개선이 되어질 것이다. 

그때 마다 변경된 사항들에 대해서 설명을 해 나갈 것이다.

지금까지의 소스는 아래의 첨부를 참조하기 바란다.

 

WANI Grid_20190620.zip
0.39MB

다음에는 행을 추가하기 위해 고려해야 할 사항들에 대해서 알아 보기로 하자.

 

 

반응형

+ Recent posts