JY Tech

윈폼으로 설문조사 결과산출 프로그램 만들기(3) 본문

Programming/MiniProject

윈폼으로 설문조사 결과산출 프로그램 만들기(3)

J.Dragon 2023. 4. 15. 22:00

이번에는 ProMode(프로모드)를 만들 것이다.

프로모드의 경우 다음과 같은 기능들이 추가된다.

1) 서술형 응답관리 

2) 객관식 응답을 엑셀로 저장

3) 객관식 응답의 자동 생성 및 행/열의 동적 수정 

 

먼저 ProModeSetting.cs를 만들어 준다

해당 폼에서는 ProMode에 진입하기 전 질문과 선택지의 개수를 전달하는 기능을 구현한다

 

이 전달기능은 지금 배워두면 다른 곳에도 써먹을 수 있으니 잘 알아두자

필자의 경우 ProModeSetting을 위와 같이 디자인 했다.

 

질문의 개수대로 우리가 만든 사용자 정의 컨트롤을 생성하는 것이고 선택지의 개수에 따라 어떤 사용자 정의 컨트롤을 쓸 지 정해지는 것이다.

 

시작 버튼을 더블클릭하여 아래와 같은 코드를 넣어주자

ProMode newform = new ProMode();
{
	if (textBox1.Text == "0")
	{
		ProMode.name = "";
	}
	else
	{
		ProMode.name = textBox1.Text;
	}
}
if (radioButton1.Checked == true) //여기부터 각각 선택지의 개수를 의미함
{
	ProMode.ans = "1";
}
else if (radioButton2.Checked == true)
{
	ProMode.ans = "2";
}
else if (radioButton3.Checked == true)
{
	ProMode.ans = "3";
}
else if (radioButton4.Checked == true)
{
	ProMode.ans = "4";
}
else if (radioButton5.Checked == true)
{
	ProMode.ans = "5";
}
else if (radioButton6.Checked == true)
{
	ProMode.ans = "6";
}
else
{
	ProMode.ans = "";
}
newform.Show();

아마 ProMode쪽에 오류가 뜰 것이다. ProMode.cs가 없으니 당연하다

 

이제 ProMode를 구성해 보자

참고로 ProMode의 폼에는 들어갈 것이 많아서 size를 크게 하는 것이 좋다. 필자는 1467,762로 설정했다

 

필자가 구성한 ProMode UI이다. 꼭 이것과 같지 않아도 된다. 단지 예시일 뿐이다

'객관식 응답'이라고 써있고 그려진 하얀 테두리는 groubox이며 그 안에 flowLayoutPanel과 버튼들을 넣어줬다. 그 아래의 검정테두리 상자는 groupbox 밖에 위치하며 dataGridView다. 해당 영역에서는 복사 붙여넣기 기능이 활용되며 결과가 엑셀로 저장되니 flowLayoutPanel로 구성하지 않도록 유의하자

 

옆의 '주관식 응답'이라고 써있는 하얀 테두리는 새로운 groupbox이며 그 안에 또 다른 flowLayoutPanel과 버튼을 넣어줬다.

각 버튼들은 groupbox안에, flowLayoutPanel 밖에 위치해 있다. 유의하자. 

 

이제부터는 코드가 조금 복잡해진다

 

일단 폼의 아무곳이나 우클릭하고 코드보기를 통해 ProMode의 코드로 들어오자

 

public ProMode()
{
	InitializeComponent();
}

라고 써있는 바로 위에 아래와 같은 코드를 넣어준다

 

public int line = 1; //질문의 개수를 동적으로 변경시킬 때 userControl의 label1 값을 변경하기 위한 변수
public int wLine = 1; //서술형 줄 수 표기를 위한 변수
public int cLine = 0; //선택지의 갯수를 변경할 때 기존 질문의 개수를 저장하기 위한 변수
public UserControl1[] btn = new UserControl1[501]; //userControl1번을 저장하기 위한 배열
public UserControl2[] btn21 = new UserControl2[501]; //userControl2번을 저장하기 위한 배열
public UserControl3[] btn31 = new UserControl3[501]; //userControl3번을 저장하기 위한 배열
public UserControl4[] btn41 = new UserControl4[501]; //userControl4번을 저장하기 위한 배열
public UserControl6[] btn61 = new UserControl6[501]; //userControl5번을 저장하기 위한 배열
public UserControl7[] btn71 = new UserControl7[501]; //userControl6번을 저장하기 위한 배열
public UserControl8[] btn81 = new UserControl8[501]; //userControl8번을 저장하기 위한 배열
public static string name; //ProModeSetting에서 갖고 온 질문의 개수
public static string ans; //ProModeSetting에서 갖고 온 선택지의 개수
public static string[] gridRes = new String[8]; //girdview에 값을 추가해주기 위한 변수
public static int lineNum = 0;
public static int totalGap = 0;

앞서 우리는 ProModeSetting에서 ProMode.ans = "1"; 라고 적었다. 이후 ProMode로 전환되면서 ProMode의 ans라는 변수에 1을 전달 해 준 것이다.

 

즉 값을 전달하기 위해서는 다음과 같은 과정을 거친다고 보면 된다. A가 값을 보내는 폼, B가 값을 받는 폼이라고 가정해보자

A폼에서 B 폼의 test라는 변수에 right라는 값을 전달한다면

//B에 사용되는 코드(값을 받는 폼)
public static string test; //public static으로 선언하자


//A에 사용되는 코드(값을 받는 폼)
B newform = new B();
B.test = "right";
newform.Show();

위와같이 작성하면 되는 것이다

 

이번에는 ProMode가 Load됐을 때의 코드를 구현하자

ProMode의 여백을 더블클릭하거나 우측하단의 속성창을 통해 Load 이벤트를 만들어주고

아래와 같은 코드를 넣어주자

try
{
    Form1.mod = "pro";
    DataTable table = new DataTable();
    for (int i = 1; i <= Convert.ToInt32(ans) + 1; i++) //dataGridView에 앞서 설정한 선택지와 응답의 개수에 따라 적절한 테이블을 생성하는 코드
    {
    	table.Columns.Add(i + "번 응답", typeof(string));
    }
    for (int i = 1; i < Convert.ToInt32(name); i++)
    {
    	table.Rows.Add("");
    }
    dataGridView1.DataSource = table;
    switch (ans) //객관식 영역의 레이아웃 패널에 알맞은 사용자 정의 컨트롤을 넣기 위한 코드
    {
    	case "1":
            for (int i = 0; i < Convert.ToInt32(name); i++)
            {
                this.userControl21 = new UserControl2();
                flowLayoutPanel1.Controls.Add(userControl21);
                btn21[line] = userControl21;
                userControl21.label1.Text = Convert.ToString(line);
                line += 1;
            }
            break;
        case "2":
            for (int i = 0; i < Convert.ToInt32(name); i++)
            {
                this.userControl31 = new UserControl3();
                flowLayoutPanel1.Controls.Add(userControl31);
                btn31[line] = userControl31;
                userControl31.label1.Text = Convert.ToString(line);
                line += 1;
            }
            break;
        case "3":
           for (int i = 0; i < Convert.ToInt32(name); i++)
           {
                this.userControl41 = new UserControl4();
                flowLayoutPanel1.Controls.Add(userControl41);
                btn41[line] = userControl41;
                userControl41.label1.Text = Convert.ToString(line);
                line += 1;
            }
            break;
        case "4":
            for (int i = 0; i < Convert.ToInt32(name); i++)
            {
                this.userControl11 = new UserControl1();
                flowLayoutPanel1.Controls.Add(userControl11);
                btn[line] = userControl11;
                userControl11.label1.Text = Convert.ToString(line);
                line += 1;
            }
            break;
        case "5":
            for (int i = 0; i < Convert.ToInt32(name); i++)
            {
                this.userControl61 = new UserControl6();
                flowLayoutPanel1.Controls.Add(userControl61);
                btn61[line] = userControl61;
                userControl61.label1.Text = Convert.ToString(line);
                line += 1;
             }
             break;
        case "6":
            for (int i = 0; i < Convert.ToInt32(name); i++)
            {
                this.userControl71 = new UserControl7();
                flowLayoutPanel1.Controls.Add(userControl71);
                btn71[line] = userControl71;
                userControl71.label1.Text = Convert.ToString(line);
                line += 1;
             }
             break;
        }
    }
    catch
    {
        MessageBox.Show("다음과 같은 설정 오류로 인해 프로그램을 시작할 수 없습니다. 아래 사항들을 다시 확인 해 주세요\n1. 질문의 개수를 입력하지 않았습니다.\n2. 질문의 개수를 0 혹은 500초과로  입력했습니다.\n3. 질문의 개수에 " +
                    "숫자가 아닌 다른 것을 입력했습니다. \n4. 선택지의 개수를입력하지 않았습니다. \n5. 초기 설정이 어렵다면 BasicMode를 사용하거나 사용법을 다시 확인 해 보세요.", "설정 오류!");
        this.Close();
    }

※티스토리 코드블럭은 라인정렬이 안되는것 같다.. 노가다로 최대한 맞췄으나 비쥬얼스튜디오의 코드정렬을 이용해 정리하자...

 

코드가 길긴 하지만 똑같은 작업의 반복이라 그다지 어렵지 않다. 차근차근 읽어보고 각 라인이 어떤 기능을 하는지 살펴보자. 주석으로 가이드라인을 잡았기 때문에 쉽게 감을 잡을 수 있을 것이다.

 

알고리즘을 간략하게 설명하면 ProModeSetting에서 name과 ans를 가지고 오는데 ans가 특히 중요하다

사용자가 선택한 ans(라디오 버튼들의 값)에 따라 패널에 알맞은 컨트롤을 넣어주고 dataGridView에도 띄우는 것이다.

 

참고로 Form1.cs에도 

public Form1()
{
	InitializeComponent();
}

위에

public static string mod = "";

를 넣어줘야 한다. mod는 basicmode와 promode를 구분하는 것인데 급한건 아니니 일단 여기까지만 해주자

 

※ProMode에 위 코드를 넣었을 때 userControl21, userControl31같은 곳에 빨간 줄이 쳐진다면

https://jy-tech.tistory.com/10

 

윈폼으로 설문조사 결과산출 프로그램 만들기(2)

이제 버튼을 누르면 해당 버튼의 숫자가 증가/감소하고 숫자의 합계가 나오는 기능을 구현해보자 먼저 UserControl1.cs에 다음과 같은 내용을 넣어주자 private void btn_MouseUp(object sender, MouseEventArgs e) {

jy-tech.tistory.com

 

이 포스트를 다시보고오자

 

폼에 패널이 없기 때문에 발생한 오류이다. 위 포스팅과 그대로 해결하면 된다.

단 넣어준 패널들은 보이지 않게 알아서 숨기던가 View를 False처리하자

 

이제 아직까지 작업한 것을 확인해 보자

Form1(메인폼)에 버튼을 넣고 ProModeSetting과 연결해주자(아직 UserControl8이 없기 때문에 public UserControl8[] btn81 코드는 주석처리 해준다)

 

메인폼에서 ProMode를 누르면

 

이런 화면이 뜰 것이다.

질문의 개수에 3을 선택지의 개수를 7을 선택해보자

 

이렇게 뜰 것이다.

즉 질문의 개수는 행의 개수, 선택지의 개수는 열의 개수를 의미하는 것이다.

앞서 질문의 개수에 제한을 뒀지만 500개나 가능하며 선택지의 개수도 2~7개까지 있기 때문에 이제 정말 웬만한 객관식 설문조사에는 다 대응할 수 있다. 

 

다음시간에는 ▲, ▼, ◀, ▶ 버튼에 기능을 넣어줄 것이다.