반응형

[그림 4-1] 추상 팩토리 패턴을 적용한 Header 생성 관련 Class Diagram

지난 번 강좌에서 보았던 추상 팩토리 패턴의 Header 생성 클래스에 대해서 살펴 보기로 하자.

 

공통 Header 정보를 관리하는 추상클래스 Header 클래스를 살펴보자.

추상 클래스인 Header에는 반드시 가져야 하는 공통 속성 정보들을 관리하도록 구현했다.

각 속성 정보들은 외부에서 getter, setter 할 수 있도록 Property 형태로 제공한다.

 

public abstract class Header
{
    #region 변수
    private int index;  //Index
    private string columnId;    //컬럼 ID
    private string title;   //컬럼 타이틀
    private int left;   //컬럼 시작위치
    private int width;  //컬럼 폭
    private HorizontalAlignment headAlign;  //컬럼 타이틀 정렬위치
    private HorizontalAlignment textAlign;  //컬럼 내용 정렬위치
    private bool visible = true;    //컬럼 Visible 여부
    #endregion 변수

    #region Property
    public int Index
    {
        get { return index; }
        set { index = value; }
    }
    public string ColumnId {
        get { return columnId; }
        set { columnId = value; }
    }
    public string Title
    {
        get { return title; }
        set { title = value; }
    }
    public int Left
    {
        get { return left; }
        set { left = value; }
    }
    public int Width
    {
        get { return width; }
        set { width = value; }
    }
    public HorizontalAlignment HeadAlign
    {
        get { return headAlign; }
        set { headAlign = value; }
    }
    public HorizontalAlignment TextAlign {
        get { return textAlign; }
        set { textAlign = value; }
    }
    public bool Visible
    {
        get { return visible; }
        set { visible = value; }
    }
    #endregion Property
}

 

Header Type에 따라 Grid Header의 모습이 다양하게 그려질 수 있도록 공통 속성 외에 추가 속성과 생성자를 정의할 수 있도록 Header 클래스를 상속 받아서 구현한 클래스를 만들 수 있도록 했다.

향 후 Grid Control의 모습이 어느 정도 완성이 되면 다른 형태의 Grid Header를 만들어야 할 경우 Header 클래스를 상속받아서 구현한 클래스를 만들게 될 것이다.

현재는 기본 Header를 그릴 수 있는 DefaultHeader라는 클래스를 만들었다. 

DefaultHeader 클래스는 추상 클래스를 상속받아서 생성자를 6개 형태로 만들었다. 생성자 호출 시에 속성 정보를 파라미터로 받아서 처리할 수 있도록 하기 위해서 이다.

 

    public class DefaultHeader : Header
    {        
        public DefaultHeader()
        {
            this.ColumnId = "";
            this.Title = "";
            this.Width = 90;
            this.HeadAlign = HorizontalAlignment.Center;
            this.TextAlign = HorizontalAlignment.Left;
            this.Visible = true;
        }

        public DefaultHeader(string fieldName, string title, int width, HorizontalAlignment headAlign, HorizontalAlignment txtAlign, bool visible)
        {
            this.ColumnId = fieldName;
            this.Title = title;
            this.Width = width;
            this.HeadAlign = headAlign;
            this.TextAlign = txtAlign;
            this.Visible = visible;
        }
        public DefaultHeader(string fieldName, string title, int width, HorizontalAlignment txtAlign, bool visible)
        {
            this.ColumnId = fieldName;
            this.Title = title;
            this.Width = width;
            this.HeadAlign = HorizontalAlignment.Center;
            this.TextAlign = txtAlign;
            this.Visible = visible;
        }

        public DefaultHeader(string fieldName, string title, HorizontalAlignment txtAlign, bool visible)
        {
            this.ColumnId = fieldName;
            this.Title = title;
            this.Width = 100;
            this.HeadAlign = HorizontalAlignment.Center;
            this.TextAlign = txtAlign;
            this.Visible = visible;
        }

        public DefaultHeader(string fieldName, string title, int width, bool visible)
        {
            this.ColumnId = fieldName;
            this.Title = title;
            this.Width = width;
            this.HeadAlign = HorizontalAlignment.Center;
            this.TextAlign = HorizontalAlignment.Center;
            this.Visible = visible;
        }

        public DefaultHeader(string fieldName, string title, int width, HorizontalAlignment txtAlign)
        {
            this.ColumnId = fieldName;
            this.Title = title;
            this.Width = width;
            this.HeadAlign = HorizontalAlignment.Center;
            this.TextAlign = txtAlign;
            this.Visible = true;
        }        
    }

 

Grid Header를 생성하기 위해서 Header 정보를 추가(Add)하고 그리기 위한 메소드를 지정하는 추상 클래스를 만든다.

    public abstract class HeaderGenerator
    {
        protected List _headers = new List(); 

        protected int topHeaderHeight = 20;   //Grid의 Header 높이
        protected int leftHeaderWidth = 22; //Grid의 맨 왼쪽의 첫번째 빈Column Width
        protected Font headerFont = new Font("맑은 고딕", 9);
        protected SolidBrush blackBrush = new SolidBrush(Color.Black);

        public int TopHeaderHeight
        {
            get { return topHeaderHeight; }
            set { topHeaderHeight = value; }
        }

        public int LeftHeaderWidth
        {
            get { return leftHeaderWidth; }
            set { leftHeaderWidth = value; }
        }

        public Font HeaderFont
        {
            get { return headerFont; }
            set { headerFont = value; }
        }

        public SolidBrush BlackBrush
        {
            get { return blackBrush; }
            set { blackBrush = value; }
        }

        public HeaderGenerator() { }

        public abstract void AddHeaders(object obj);
        public abstract List GetHeaders(); 

        public abstract void HeaderClear();                         

        public abstract void DrawHeaders(int firstVisibleCol, int lastVisibleCol, int controlWidth, Graphics graphics, Rectangle rect);

    }

 

이제 HeaderGenerator라는 추상 클래스를 상속받아서 Header Type별로 Header를 그리는 클래스를 만들어야 한다.

현재는 기본 Header인 DefaultHeader를 설정하고 그리기 위한 DefaultHeaderGenerator 클래스를 만들어야 한다.

DefaultHeaderGenerator 클래스는 Grid의 Header 영역을 직접 그리는 영역이다.

특히 주의 깊게 봐야 할 부분은 DrawHeaders 메소드 부분이다. 

Grid의 Row와 Column이 아무리 많이 있다고 하더라도 Grid Control 사이즈에 맞는 영역의 Row와 Column만 사용자에게 제공하면 된다.

따라서 스크롤바를 움직이거나 움직이지 않았을 때 Grid Control에서 보여줘야 할 Row와 Column을 계산해서 찾아내야 한다. Header의 경우 항상 Control의 최상단 영역에 그려지는 부분이기에 Grid Control 영역에 맞는 첫번재 컬럼과 마지막 컬럼을 찾아서 헤더 정보를 그리면 된다.

그렇기에 DrawHeaders메소드의 파라미터로 firstVisibleCol, lastVisibleCol를 받고 있는 것이다.

 

    public class DefaultHeaderGenerator : HeaderGenerator
    {        
        /// 컬럼 헤더 정보를 설정
        public override void AddHeaders(object obj)
        {
            this._headers.Add(obj as Header);            
        }

        /// 컬럼 헤더 정보를 반환
        public override List GetHeaders()
        {
            return this._headers;
        }

        /// 헤더 정보를 Clear한다.
        public override void HeaderClear()
        {
            this._headers.Clear();
        }

        /// Header 그리기                 
        public override void DrawHeaders(int firstVisibleCol, int lastVisibleCol, int controlWidth, Graphics graphics, Rectangle rect)
        {
            SolidBrush brush = new SolidBrush(SystemColors.ControlLight);
            Pen pen = new Pen(Color.LightGray);

            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++)
            {
                columnStartX = this._headers[i].Left + leftHeaderWidth;
                int headerWidth = this._headers[i].Width;

                //보여지는 컬럼의 폭이 컨트롤의 폭 보다 클경우 
                if (this._headers[i].Left + headerWidth > controlWidth)
                {
                    headerWidth = controlWidth - this._headers[i].Left - leftHeaderWidth - 3;
                }
                //헤더 영역의 사각형을 채우고 테두리를 그린다.
                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);
            }
        }
    }
}

WANI Grid.zip
0.25MB

 

Grid Header를 그리기 위한 기본 클래스들에 대해서 살펴 보았다.

지금까지의 설명을 담은 소스는 위의 첨부 파일을 참조하면 된다.

다음 강좌에서는 Grid Header 영역을 그리기 위한 부분들을 추가해서 헤더가 그려지는 부분을 완성하도록 해보겠다.

이 강좌는 Step By Step 형태로 조그마한 기능 하나 하나를 추가/보완해 가면서 전체 기능을 완성하는 과정을 보여주고 나 또한 단계별 학습을 통해서 기능을 하나씩 완성해 가고자 한다.

 

단계별 진행을 보면서 추가 또는 보완했으면 하는 아이디어가 있다면 언제든 댓글을 달아주시길....

반응형

+ Recent posts