본문 바로가기
C#/기능경기대회 정보기술 과제 풀이

2025년 지방기능경기대회 정보기술 1과제 C# 과제 풀이 (6)

by 은메달 수집가 2025. 5. 30.

지난 포스팅에서 마무리하지 못한 마지막 분석폼 풀이 정리를 마무리하고, 지방기능경기대회 정보기술 직종 1 과제 풀이 관련 포스팅을 모두 마무리하고자 한다.


분석폼 풀이

분석폼 디자인

드디어 대망의 마지막, 분석폼이다. 폼 구조는 상단 콤보박스를 제외하고 ChartControl 2개만 배치하면 되는 구조기 때문에, 상세 레이아웃 배치는 Skip 하고 바로 코드 설명을 확인하자.

1) 폼이 실행되면 초기 화면은 [그림 13-1]과 같이 나타내시오.
2) 콤보박스를 다음과 같이 제어하시오.
    가. 아이템은 모든 연령(전체, 성인, 청소년, 어린이, 유아)으로 구성하시오.
    나. 콤보박스의 아이템을 변경하면 [그림 13-2]를 참고하여 막대 차트에 나타나도록 제어하시오. (해당 항목의 도착지 기준으로 예약 횟수로 차트 작성)
    다. 원형 차트의 색은 막대 차트의 범례 색과 동일하게 나타내시오. (단, 전체 제외.)
3) 원형 차트는 연령대별 예약 현황에 대하여 나타내고, 해당 값을 [그림 13-1]과 같이 차트에 표시하시오.
4) 폼을 닫으면 이전 폼으로 이동하시오.

AnalysisForm.cs (분석폼) 전체 코드

public partial class AnalysisForm : TemplateForm
{
    public AnalysisForm()
    {
        InitializeComponent();
    }

    private void cmbList_SelectedIndexChanged(object sender, EventArgs e)
    {
        if (this.cmbList.SelectedIndex != -1)
        {
            this.SuspendLayout();

            if (this.cmbList.SelectedIndex == 0)
            {
                this.chartCircle.Visible = true;
                this.Size = this.MaximumSize;

                UpdateCircleChart();
            }
            else
            {
                this.chartCircle.Visible = false;
                this.Size = this.MinimumSize;
            }

            UpdateBarChart();

            this.ResumeLayout();
        }
    }

    private void AnalysisForm_Load(object sender, EventArgs e)
    {
        this.cmbList.SelectedIndex = 0;
    }

    /// <summary>
    /// 가로 차트 업데이트
    /// </summary>
    private void UpdateBarChart()
    {
        this.chartBar.Series.Clear();

        string[] xValues = this.db.location.Select(x => x.lname).Distinct().OrderBy(x => x).ToArray();
        string[] series = new string[] { "전체", "성인", "청소년", "어린이", "유아" };
        Color[] colors = new Color[] {  };

        if (this.cmbList.SelectedIndex > 0) series = new string[] { this.cmbList.SelectedItem.ToString() };


        int maxVal = 0;

        for(int idx = 0; idx < series.Length; idx++) 
        {
            string ageCategory = series[idx];

            Series sr = new Series(ageCategory);
            int[] yValues = new int[xValues.Length];

            sr.ChartType = SeriesChartType.Column;


            if(ageCategory == "전체")
            {
                for(int i = 0; i < xValues.Length; i ++)
                {
                    string location = xValues[i];
                    yValues[i] = this.db.reservation.Count(x => x.schedule.location.lname == location);
                }
            }
            else
            {
                for (int i = 0; i < xValues.Length; i++)
                {
                    string location = xValues[i];

                    int cnt = 0;

                    foreach (reservation res in this.db.reservation.Where(x => x.schedule.location.lname == location))
                    {
                        if (res.user != null && SolutionUtil.ConvertAgeToStringCategory(res.user) == ageCategory)
                        {
                            cnt++;
                        }
                    }

                    yValues[i] = cnt;
                }
            }

            switch (ageCategory)
            {
                case "전체": sr.Color = Color.FromArgb(65, 140, 240); break;
                case "성인": sr.Color = Color.Orange; break;
                case "청소년": sr.Color = Color.Red; break;
                case "어린이": sr.Color = Color.SteelBlue; break;
                case "유아": sr.Color = Color.LightGray; break;

            }

            for (int i = 0; i < xValues.Length; i++) 
            {
                sr.Points.AddXY(xValues[i], yValues[i]);
                if (maxVal < yValues[i]) maxVal = yValues[i];
            }

            this.chartBar.Series.Add(sr);
            this.chartBar.DataBind();
        }

        maxVal += 20;

        this.chartBar.ChartAreas[0].AxisY.Maximum = maxVal;

        this.chartBar.DataBind();
        this.chartBar.Invalidate();
    }

    private void UpdateCircleChart()
    {
        Series sr = this.chartCircle.Series[0];

        string[] xValues = new string[] { "성인", "청소년", "어린이", "유아" };
        int[] yValues = new int[xValues.Length];

        sr.Points.Clear();

        for (int i = 0; i < xValues.Length; i++)
        {
            string ageCategory = xValues[i];

            int cnt = 0;
            foreach(reservation res in this.db.reservation)
            {
                if (res.user != null && SolutionUtil.ConvertAgeToStringCategory(res.user) == ageCategory)
                    cnt++;

            }
            yValues[i] = cnt;
        }

        for (int i = 0; i < xValues.Length; i++)
        {
            sr.Points.AddXY(xValues[i], yValues[i]);
        }

        this.chartCircle.DataBind();
        this.chartCircle.Invalidate();
    }
}

AnalysisForm.cs (분석폼) ComboBox SelectedIndexChanged 이벤트 코드 설명

private void cmbList_SelectedIndexChanged(object sender, EventArgs e)
{
    if (this.cmbList.SelectedIndex != -1)
    {
        this.SuspendLayout();

        if (this.cmbList.SelectedIndex == 0)
        {
            this.chartCircle.Visible = true;
            this.Size = this.MaximumSize;

            UpdateCircleChart();
        }
        else
        {
            this.chartCircle.Visible = false;
            this.Size = this.MinimumSize;
        }

        UpdateBarChart();

        this.ResumeLayout();
    }
}
  • if (this.cmbList.SelectedIndex != -1) { .... }
    콤보박스 컨트롤을 사용할 때 늘 사용하는 제어 로직이다. 사용자가 콤보박스 목록 중에서 하나를 선택했을 때에만 동작할 수 있게 제어하는 코드다.
  •  if (this.cmbList.SelectedIndex == 0)
     {
         this.chartCircle.Visible = true;
         this.Size = this.MaximumSize;

         UpdateCircleChart();
     }
     else
     {
         this.chartCircle.Visible = false;
         this.Size = this.MinimumSize;
     }
    사용자가 콤보박스에서 "전체"를 선택한 경우에는 막대 차트와 원형 차트 모두 보여야 하고, 특정 연령대를 선택한 경우에는 막대 차트만 보여야 하기에 위와 같이 작성하였다. Form의 MinimumSize, MaximumSize를 미리 정의하여 상황에 맞는 폼 사이즈로 될 수 있게 하였다.
  • UpdateBarChart();
    막대 차트의 데이터를 업데이트하기 위해 관련 메서드를 호출하고 있다.

AnalysisForm.cs (분석폼) UpdateBarChart 메서드 코드 설명

/// <summary>
/// 가로 차트 업데이트
/// </summary>
private void UpdateBarChart()
{
    this.chartBar.Series.Clear();

    string[] xValues = this.db.location.Select(x => x.lname).Distinct().OrderBy(x => x).ToArray();
    string[] series = new string[] { "전체", "성인", "청소년", "어린이", "유아" };
    Color[] colors = new Color[] {  };

    if (this.cmbList.SelectedIndex > 0) series = new string[] { this.cmbList.SelectedItem.ToString() };

    int maxVal = 0;

    for(int idx = 0; idx < series.Length; idx++) 
    {
        string ageCategory = series[idx];

        Series sr = new Series(ageCategory);
        int[] yValues = new int[xValues.Length];

        sr.ChartType = SeriesChartType.Column;


        if(ageCategory == "전체")
        {
            for(int i = 0; i < xValues.Length; i ++)
            {
                string location = xValues[i];
                yValues[i] = this.db.reservation.Count(x => x.schedule.location.lname == location);
            }
        }
        else
        {
            for (int i = 0; i < xValues.Length; i++)
            {
                string location = xValues[i];

                int cnt = 0;

                foreach (reservation res in this.db.reservation.Where(x => x.schedule.location.lname == location))
                {
                    if (res.user != null && SolutionUtil.ConvertAgeToStringCategory(res.user) == ageCategory)
                    {
                        cnt++;
                    }
                }

                yValues[i] = cnt;
            }
        }

        switch (ageCategory)
        {
            case "전체": sr.Color = Color.FromArgb(65, 140, 240); break;
            case "성인": sr.Color = Color.Orange; break;
            case "청소년": sr.Color = Color.Red; break;
            case "어린이": sr.Color = Color.SteelBlue; break;
            case "유아": sr.Color = Color.LightGray; break;

        }

        for (int i = 0; i < xValues.Length; i++) 
        {
            sr.Points.AddXY(xValues[i], yValues[i]);
            if (maxVal < yValues[i]) maxVal = yValues[i];
        }

        this.chartBar.Series.Add(sr);
        this.chartBar.DataBind();
    }

    maxVal += 20;

    this.chartBar.ChartAreas[0].AxisY.Maximum = maxVal;

    this.chartBar.DataBind();
    this.chartBar.Invalidate();
}
  • 사용자가 콤보박스에서 "전체"를 선택한 경우에는 전체 카테고리를 포함하여 모든 연령대에 대해서 series 객체가 생성되고, chart에 등록되게 하는 코드다.
  • 사용자가 "전체"가 아닌 특정 연령대 구분을 선택한 경우에는 해당 연령대만 series 객체를 생성하여 동작할 수 있게 하였다.
  • this.chartBar.DataBind();
    차트 데이터를 변경하고, 항상 DataBind() 메서드를 호출해야 변경된 데이터에 맞게 차트가 다시 그려지게 된다. 이 메서드를 호출하지 않으면 데이터를 아무리 변경해도 화면에 차트가 변경이 되지 않는 상황을 마주할 수 있다.

AnalysisForm.cs (분석폼) UpdateCircleChart 메서드 코드 설명

private void UpdateCircleChart()
{
    Series sr = this.chartCircle.Series[0];

    string[] xValues = new string[] { "성인", "청소년", "어린이", "유아" };
    int[] yValues = new int[xValues.Length];

    sr.Points.Clear();

    for (int i = 0; i < xValues.Length; i++)
    {
        string ageCategory = xValues[i];

        int cnt = 0;
        foreach(reservation res in this.db.reservation)
        {
            if (res.user != null && SolutionUtil.ConvertAgeToStringCategory(res.user) == ageCategory)
                cnt++;

        }
        yValues[i] = cnt;
    }

    for (int i = 0; i < xValues.Length; i++)
    {
        sr.Points.AddXY(xValues[i], yValues[i]);
    }

    this.chartCircle.DataBind();
    this.chartCircle.Invalidate();
}
  • 원형 차트의 경우에는 ChartControl에 기본적으로 등록되어 있는 Series 객체를 사용해서 해당 객체에 등록되어 있는 데이터(Points)만 수정하여 주면 된다. 
  • Points 컬렉션 객체를 Clear() 하고, 알맞은 데이터를 구하여 AddXY 메서드를 호출하여 데이터를 등록해 주면 된다.

마무리하며...

지방기능경기대회 과제 풀이 포스팅이 6개까지 작성될 줄은 몰랐는데 정리하면서 코드를 하나씩 설명하다 보니 내용이 많이 길어진 것 같다. 처음 시작하는 선수들을 위해 최대한 자세히 설명을 하려고 노력했는데 그럼에도 불구하고 조금 많이 내용이 모자란 것 같다는 생각도 든다. 

혹시, 설명이 부족하여 이해가 잘 되지 않는 선수들이 있다면 편하게 댓글로 남겨주면 추가 설명을 할 수 있도록 다양한 방법을 지원해 보겠다. (댓글로 설명하거나... 디코방을 만들거나... 등등등)

어찌 됐든 이 풀이는 참고용으로 학습용으로 사용되길 바라며, 훨씬 더 좋은 솔루션을 선수들이 찾아내서 각자의 풀이에 적용이 되길 바란다!

728x90