반응형

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

추상 팩토리 패턴의 클래스 생성을 책임지는 HeaderBuilder Class를 살펴보기로 하자.

HeaderBuilder Class는 GridType에 따른 HeaderGenerator를 상속 받은 클래스를 이용해서 Header를 그리기 위한 클래스를 생성하는 책임을 가지게 된다.

먼저 GridType에 대해서 살펴보자.

GridType은 차후에 다양한 형태의 Grid를 그릴 수 있도록 아래와 같이 3가지 타입을 정의했다. 현재는 DefaultType을 기반으로 먼저 기본 기능들을 구현할 것이다. DefaultType의 기능이 구현되고 나면 추후에 YearMonthWeekNoType과 YearMonthWeekNoDayType 등을 구현하도록 하자.

    public enum GridType
    {
        DefaultType,    //Default Type
        YearMonthWeekNoType,    //년, 월, 주차 유형
        YearMonthWeekNoDayType  //년월, 주차, 일 유형
    }

 

HeaderBuilder Class는 GridType을 설정하고 가져오기 위해서 GridType 변수와 GridType에 따른 HeaderGenerator를 설정하기 위한 HeaderGenerator 변수를 가지게 된다.

    private GridType gridType = GridType.DefaultType;   //GridType 변수 선언 및 DefaultType 설정
    private HeaderGenerator headGen;    //HeaderGenerator 변수 선언

 

설정한 GridType 값을 HeaderBuilder Class 외부에서 get/set 하기 위한 Property

    public GridType GridDisplayType
    {
        get { return gridType; }
        set { gridType = value; }
    }

 

HeaderBuilder Class의 생성자는 파라미터가 없는 Default 생성자와 GridType을 파라미터를 입력 받는 생성자를 제공

    public HeaderBuilder() { }
    public HeaderBuilder(GridType grdType)
    {
        this.gridType = grdType;
        if (gridType == GridType.DefaultType) //현재는 GridType이 DefaultType일 경우만 설정함.
        {
            if (headGen == null) 

                headGen = new DefaultHeaderGenerator(); //GridType이 DefaultType일 경우 DefaultHeaderGenerator를 설정
        }
    }

 

Grid Header의 Header정보를 추가하는 메소드

    public void AddHeader(Header header)
    {
        if (gridType == GridType.DefaultType) //현재는 GridType이 DefaultType일 경우만 설정함.
        {
            if (headGen == null) headGen = new DefaultHeaderGenerator();
            headGen.AddHeaders(header);
        }
    }

 

추가된 Header 목록을 가져오는 메소드

    public<List> GetHeaders()
    {
        return headGen.GetHeaders();
    }

 

HeaderGenerator를 반환하는 Property

    public HeaderGenerator HeaderGen
    {
        get { return headGen; }
    }

 

Header 추가 후 Header를 초기화하는 메소드에서 Header를 그리기 위해서 필요한 각 Header의 순서인 Index값과 왼쪽 시작 X 좌표값을 계산하게 된다. 

    public void InitializeHeader()
    {
        //헤더 설정이 되어져 있지 않을 경우
        if (headGen == null || headGen.GetHeaders().Count < 1) return;

        int index = 0;
        int left = 0;

       

        // 등록된 Header 정보에서 Header Index값과 Left 좌표 값을 계산한다.
        foreach (Header header in headGen.GetHeaders())
        {
            header.Index = index;
            header.Left = left;
            left += header.Width;
            index++;
        }
    }

 

Grid Header를 그리기 위해서 필요한 클래스들을 모두 만들어 보았다. 아래의 소스 코드를 실행해도 Grid Header가 그려지거나 하지는 않지만 Grid Header를 그리기 위한 준비는 되었다.

다음 시간에는 Grid Class를 만들어서 실제 Grid Header를 그리는 메소드를 구현해 보겠다.

MyProject02.zip
0.26MB

 

 

 

반응형
반응형

[그림 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 형태로 조그마한 기능 하나 하나를 추가/보완해 가면서 전체 기능을 완성하는 과정을 보여주고 나 또한 단계별 학습을 통해서 기능을 하나씩 완성해 가고자 한다.

 

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

반응형
반응형

Grid Header 부분은 Grid의 Column 각각에 대한 타이틀과 속성 정보들을 관리하는 부분이라고 볼 수 있다.
우리가 흔히 보는 Grid Control의 모습은 아래와 같다.

[그림 3-1] Grid 영역

맨 첫번째 영역인 Default Column, Grid Header 영역은 각 컬럼의 데이터 속성을 대표하는 타이틀을 보여주는 Header영역과 Row와 Column별로 구분되어 실제 데이터를 입력 받거나 보여주기 위한 Data 영역으로 구성된다.
오늘 설명하고자 하는 부분은 각 Column의 타이틀 영역인 Header 부분에 대해서 관리되어야 할 정보와 내용들에 대해서 논하고자 한다.
Grid의 Header 영역은 Grid 최상단에 위치하며 초기 고정된 높이를 가지게 되며, 또한 Grid가 처음 만들어지고 초기화 될 때 Header 영역에 대한 속성이 설정되어진다. 
Grid 초기화 시에 고려되어야 하는 부분들 중 Header 영역으로만 제한해서 생각하면 먼저 첫번째 Column인 빈 영역과 데이터를 입력하거나 보여주게 되는 Column들로 구성이 된다.
각 Header에서 관리되어야 할 정보들은 컬럼 제목, 컬럼 폭, 컬럼 시작 위치, 컬럼 타이틀 정렬 방법(좌측/중앙/우측 정렬), 컬럼 내용 정렬 방법(좌측/중앙/우측 정렬), 컬럼 ID, 컬럼 Index, 컬럼 Display 여부 등의 정보들이다.

 

항목 필드명 상세
순서 Index (index) 컬럼 순서를 의미한다.
컬럼 ID ColumnId (columnId) 컬럼 ID를 말하며, DataTable과 연동될 경우 필드 ID를 의미한다.
타이틀 Title (title) 컬럼 타이틀
컬럼 시작 위치 Left (left) 컬럼의 시작 X좌표
컬럼 폭 Width (width) 컬럼의 폭
타이틀 정렬 방법 HeadAlign (headAlign) 컬럼 타이틀 정렬 방법 (좌측/중앙/우측)
컬럼 내용 정렬 방법 TextAlign (textAlign) Data 영역의 컬럼 내용 정렬 방법 (좌측/중앙/우측)
Display 여부 Visible (visible) 컬럼 Display 여부 (true/false)

Grid Header의 고유 속성은 상기의 8개 항목으로 정의한다. 분석/설계/구현을 진행하면서 속성이 변경될 소지는 다분히 있으나, 현재까지의 분석/설계 단계에서는 8개의 항목으로 결정하고 진행하겠다.

 

Grid Control을 사용하기 위해서는 반드시 Grid Header 부분에 대한 정의가 있어야 하며, 정의된 Header 정보를 근간으로 데이터를 보여주게 된다.

Grid Header는 Header 타입에 따라 다양한 모습으로 구성될 수 있다.

Grid Header를 초기화 할때 Header Type에 따라 다양한 모습으로 구성될 수 있도록 구현되어져야 하며, Header 속성 정보가 Data 영역의 컬럼들을 제어하게 된다. 

각 컬럼을 제어하게 되는 속성은 컬럼 순서, 컬럼 내용 정렬, 컬럼 Display 여부, 컬럼의 폭 등이 된다.

 

Grid Header 초기화 시에 동적으로 Header를 생성하기 위해서 디자인 패턴으로는 추상 팩토리 패턴을 사용했다.

추상 팩토리 패턴은 구체적인 클래스에 의존하지 않고 서로 연관되거나 의존적인 객체들의 조합을 만드는 인터페이스를 제공하는 패턴을 말하며 관련성 있는 여러 종류의 객체를 일관된 방식으로 생성하는 경우에 유용하다.

 

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

Grid Header 생성을 위해서는 먼저 HeaderBuilder 클래스를 이용해서 Header 정보를 생성 후 HeaderBuilder를 WANIGrid Control에 SetHeader 메소드를 이용해서 설정을 하도록 설계 및 구현을 했다.

 

HeaderBuilder를 이용해서 Grid Header 생성은 아래와 같이 사용한다.

HeaderBuilder 생성자의 입력 파라미터로 GridDisplayType를 던지고 GridDisplayType에 따라 Grid Header의 형태가 결정되어진다.

builder.AddHeader메소드를 이용해서 DefaultHeader 클래스를 생성해서 Grid Header를 추가한다.

Header 추가가 완료 되면 InitializeHeader메소드를 이용해서 Header 속성 정보들을 초기화 한다. 초기화 완료 후 HeaderBuilder 클래스를 WANIGrid Control의 SetHeader메소드를 호출해서 설정하는 것으로 Grid Header 설정은 마무리 된다.

 

아래는 HeaderBuilder 생성 후 Grid Header 설정 예.

HeaderBuilder builder = new HeaderBuilder(this.waniGrid.GridDisplayType);
builder.AddHeader(new DefaultHeader("Col01", "Column 01", 100, HorizontalAlignment.Center, HorizontalAlignment.Left, true));
builder.AddHeader(new DefaultHeader("Col02", "Column 02", 100, HorizontalAlignment.Center, HorizontalAlignment.Left, true));
builder.AddHeader(new DefaultHeader("Col03", "Column 03", 100, HorizontalAlignment.Center, HorizontalAlignment.Left, true));
builder.AddHeader(new DefaultHeader("Col04", "Column 04", 100, HorizontalAlignment.Center, HorizontalAlignment.Left, true));
builder.AddHeader(new DefaultHeader("Col05", "Column 05", 100, HorizontalAlignment.Center, HorizontalAlignment.Left, true));
builder.AddHeader(new DefaultHeader("Col06", "Column 06", 100, HorizontalAlignment.Center, HorizontalAlignment.Left, true));
builder.AddHeader(new DefaultHeader("Col07", "Column 07", 100, HorizontalAlignment.Center, HorizontalAlignment.Left, true));
builder.AddHeader(new DefaultHeader("Col08", "Column 08", 100, HorizontalAlignment.Center, HorizontalAlignment.Left, true));
builder.AddHeader(new DefaultHeader("Col09", "Column 09", 100, HorizontalAlignment.Center, HorizontalAlignment.Left, true));
builder.AddHeader(new DefaultHeader("Col10", "Column 10", 100, HorizontalAlignment.Center, HorizontalAlignment.Left, true));
builder.InitializeHeader();
this.waniGrid.SetHeader(builder);

 

다음 시간에는 위에 설명한 방법대로 구현한 Header 관련 클래스에 대한 설명과 소스를 같이 보도록 하자.

반응형

+ Recent posts