ProgressBar는 작업 진행률을 사용자에게 보여주거나 할 때 쓰이는 도구이다.

흔히 로딩바라고 부르는것과 비슷하다.


만들어본 동작은 간단하다. 아래 그림 1,2,3과 같이

버튼을 누르면 ProgressBar가 0에서 100까지 진행한 뒤 진행완료 메시지를 출력하는것.


<그림 1>


<그림 2>


<그림 3>


ProgressBar 도구가 이미 만들어져 있기에 사용법은 간단하다.

도구 상자의 ProgressBar를 찾아 넣기만 하면 끝이다.

처음 생성시키면 속성의 Max값과 Min값은 각각 100과 0으로 설정되어 있다.

만약 위처럼 겉모양만 해보는게 아닌 실제 작업진행률을 표시할 땐

이 Max값을 전체 작업량으로 설정하면 될 것이다.


그 외에 눈여겨 볼 속성으론 Step과 Value, Style정도가 있다.


Step 속성은 PerformStep() 메서드를 호출할 때 표시줄의 현재 위치를 증분시킬 크기를 설정할 수 있는 속성이다.

예를들어 Step값이 1이면 Max가 100 Min이 0일 때 작업이 100번 일어나야 표시줄이 다 채워지는 것.

Step속성을 지정하고 PerformStep()메서드로 진행하는 방법도 있지만

Increment(Step값)를 이용해서 진행하는 방법도 있다.


1
2
3
4
                //Increment이용
                this.progressBar1.Increment(1);
                //Step, PerformStep 이용
                this.progressBar1.PerformStep();
cs

<코드 1>


Step의 크기가 1일 때 <코드 1>의 두 코드는 같게 동작한다.


Value 에는 표시줄의 현재 진행 값이 들어간다.


Style 속성으론 표시줄의 스타일을 지정할 수 있다. 

Blocks, Continuous, Marquee 로 3가지 스타일이 있는데 OS에 따라 다른경우도 있다.

Blocks와 Continuous는 똑같이 연속적으로 증가하는 형태지만

Blocks의 경우 XP 이전의 OS에서는 블록을 쌓아가는 형태의 표시줄로 보여진다.


<그림 4 : 구버전 OS의 Blocks 스타일>


<그림 5 : Marquee 스타일>


아래는 위 그림1,2,3을 구현한 코드다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
        private void button1_Click(object sender, EventArgs e)
        {
            //backgroundWorker1.RunWorkerAsync();
            
            for (int i = 0; i < 100; i++)
            {
                //this.progressBar1.Increment(1);
                this.progressBar1.PerformStep();
                this.label1.Text = progressBar1.Value.ToString() + "%";
                Update();
                //this.label1.Refresh();
                Thread.Sleep(100);
            }
            
            if (progressBar1.Value == 100)
            {
                MessageBox.Show("진행완료");
            }
            
        }
cs

<코드 2>


동작을 구현하던 중 한가지 문제를 겪었었는데

바로 ProgressBar가 진행하는 동안 진행률을 표시해주기 위해 label.Text에 값을 넣어주는 코드가

정상적으로 동작하지 않는 문제였다.


코드 자체는 동작을 했지만 프로그래스바가 진행 완료될 때 까지 실시간으로 화면에 출력되지는 않는 문제였는데

혹시 스레드가 자식객체인 표시줄을 진행시키는 일에 할당되어 label값이 변경되어도 부모객체인 Form을 update시키질

못하는게 아닐까 생각되어 찾아보니 내부에서 따로 Update문을 추가하는 것으로 해결할 수 있었다.

<코드 2>의 10번 줄을 보면 Update문을 추가한 것을 볼 수있다. 

Update이외에도 11번 줄로처럼 Label을 Refresh시켜주는 것으로도 대체 가능했다.


Update나 Refresh말고도 BackgroundWorker를 이용하는 방법도 있다는것 같은데

몇번 시도해봤지만 어째선지 실패하여 일단 보류시켜뒀다.

반응형


스크롤바는 세로 스크롤바(VScrollBar)와 가로 스크롤바(HScrollBar) 두개가 있다.

이 중 HScrollBar를 이용해 RGB값을 변경하도록 해본다.


[그림 1]


먼저 Form을 생성해준 뒤 도구상자에서 HScrollBar을 가져와 [그림 1]처럼 놔준다.

3개의 스크롤바는 각각 R, G, B값의 0부터 255까지 수치를 맡게할것이다.


RGB값의 변화를 확인하기 위해 임시로 Label을 하나 생성한 뒤

label의 BackColor 값을 변경시키게 한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
        private void ChangeColor()
        {
            int r = this.hScrollBar1.Value;
            int g = this.hScrollBar2.Value;
            int b = this.hScrollBar3.Value;
 
            this.label1.BackColor = Color.FromArgb(r, g, b);
            this.label1.Text = String.Format("RGB 색상값 : RGB({0}, {1}, {2})", r, g, b);
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            this.label1.BackColor = Color.Black;
        }
 
        private void hScrollBar1_Scroll(object sender, ScrollEventArgs e)
        {
            ChangeColor();
        }
 
        private void hScrollBar2_Scroll(object sender, ScrollEventArgs e)
        {
            ChangeColor();
        }
 
        private void hScrollBar3_Scroll(object sender, ScrollEventArgs e)
        {
            ChangeColor();
        }
cs

[코드 1]


RGB값은 0부터 255까지밖에 값이 들어가지 않기때문에 ScrollBar의 Maximum이나 Minimum속성값을

0에서 255범위 밖의 값으로 지정해도 스크롤바를 해당 수치 넘어서까지 움직이면 오류가 뜬다.

[코드 1]처럼 스크롤 상자를 이동할 때 동작하는 Scroll이벤트를 이용해 이동시마다 RGB값 변경을 보여줄 수 있다.


하지만 제대로 동작하기 위해선 ScrollBar의 LargeChange속성을 1로 변경시켜줘야 한다.

LargeChange속성은 스크롤 막대를 클릭하거나 <Page UP> 또는 <Page Down> 키를 누를 때 스크롤 상자 위치가 변경되는 정도를 설정해두는 속성으로 기본값으로는 10이 설정되어있다.

그런데 이 속성값을 10으로 둘 경우 스크롤 상자를 끝까지 옮겨도 설정해둔 Maximum값까지 올라가지 않는 문제가 있다.

어째서 LargeChange속성이 Maximum속성 값에 직접적 영향을 끼치는지 파악하지는 못했다.


[그림 2]


정상적으로 동작하면 [그림 2]와 같은 모습이 나온다.

반응형

 

RadioButton과 CheckBox 도구(클래스)는 사용자에게 선택지를 줄 때 사용할 수 있다.


[그림 1 : 좌 라디오버튼 우 체크박스]


radiobutton과 checkbox에는 공통적으로 존재하는 이벤트로 CheckedChanged가 있다.

'Checked' 속성의 값이 변경될 때 동작하는 이벤트인데, 

이를 이용해 선택하는 동작이 있었을 때를 트리거로 다른 동작을 구현할 수 있다.


1
2
3
4
5
6
7
private void radioButton1_CheckedChanged(object sender, EventArgs e)
{
    if (sender == this.radioButton1)
    {
        //동작
    }
}
cs

[코드 1]


1
2
3
4
5
6
7
8
9
10
11
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
    if (sender == this.checkBox1)
    {
        //동작
    }
    if (this.checkBox1.Checked == false)
    {
        //동작
    }
}
cs

[코드 2]


[코드 1]의 sender == this.radioButton1 은 this.radioButton1.Checked == true 로도 사용 가능하다.

마찬가지로 [코드 2]의 sender == this.checkBox1 도 this.checkBox1.Checked == true 로 사용 가능하다.


체크박스의 경우 여러개의 체크박스를 ListBox에 넣어 묶음으로 사용 가능하게 만들어둔

CheckedListBox 도구가 따로 존재한다.

Items라는 속성을 가지며 그 안에 체크박스 항목들을 자식 컨트롤로 갖는다.

항목들을 추가하기 위해 속성 창의 Items 프로퍼티 컬랙션을 설정하거나 Designer.cs 또는 초기화 코드에서

checkedListBox1.Items.Add("항목이름"); 처럼 직접 넣을 수 있다.

추가된 항목들은 각자 0번부터 Index값을 갖는다.


[그림 2]


CheckedListBox의 경우 그냥 CheckBox와는 달리 Item을 선택했을때 발생하는 SelectedIndexChanged 이벤트와

Item의 Checked 상태가 변경될 때 발생하는 ItemCheck 이벤트가 있다.


1
2
3
4
5
6
        private void checkedListBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            //if(this.checkedListBox1.SelectedIndex != -1){
                this.label1.Text = this.checkedListBox1.SelectedItem.ToString();
            //}
        }
cs

[코드 3]


SelectedIndexChanged 이벤트는 SelectedIndex 값이 변경될 때 발생하는데

아무것도 선택된 항목이 없을 시 SelectedIndex 는 -1값을 갖고있다. 이를 이용해 조건문을 만들 수 있지만

[코드 3]처럼 해도 이벤트 발생을 위해선 일단 SelectedIndex 값이 변경되어야 하기에 동작은 차이가 없다.


1
2
3
4
5
6
7
8
9
10
11
12
13
        private void itemCheck_Changed(object sender, ItemCheckEventArgs e)
        {
            string item = this.checkedListBox1.SelectedItem.ToString();
            this.label1.Text = e.NewValue.ToString();
            if (e.NewValue == CheckState.Checked)
            {
                this.listBox1.Items.Add(item);
            }
            else
            {
                this.listBox1.Items.Remove(item);
            }
        }
cs

[코드 4]


ItemCheck 이벤트에선 e.NewValue로 현재 항목의 Checked 상태를 가져올 수 있다.

상태로는 Checked와 Unchecked 그리고 Indeterminate가 있다.

Checked는 선택된 상태 Unchecked는 선택되지 않은 상태 Indeterminate는 결정되지 않은 상태로


[그림 3 출처 : https://css-tricks.com/indeterminate-checkboxes/]


Indeterminate는 [그림 3]의 Tall Things 같은 경우 사용한다 생각하면 될 듯 하다.


[코드 4]의 5번 라인 처럼 현재 선택된 항목의 체크 상태를 불러와 CheckState를 이용해 비교하여 조건문을 만들 수 있다.

반응형


시간이 흐름에 따라 계속해서 값을 변경시켜줘야 하는 경우 Timer 클래스를 이용할 수 있다.


[그림 1]


Timer를 처음 생성하면 기본적으로 Enabled가 False로 되어있어 동작하지 않는다.

그렇기에 따로 Enabled속성을 true로 바꿔주어야 한다.


Timer엔 Tick이라는 EventHandler가 있다. 

이 Tick을 이용해 실시간으로 이벤트를 발생시킬 수 있는것.


예를 들어 DateTime을 이용해 현재 시간을 실시간 출력하고자 할때


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
private void Form1_Load(object sender, EventArgs e)
{
    string strMsg = String.Empty;
    strMsg = String.Format("{0}년\r\n{1}월\r\n{2}일\r\n" + "{3}시\r\n{4}분\r\n{5}초\r\n",
        DateTime.Now.Year,
        DateTime.Now.Month,
        DateTime.Now.Day,
        DateTime.Now.Hour,
        DateTime.Now.Minute,
        DateTime.Now.Second);
    this.textBox1.Text = strMsg;
 
    // 또는 아래와 같은 방식으로도 표현 할 수 있다.
    // StringBuilder 클래스 사용 <- 긴 문자열 처리할 때
    System.Text.StringBuilder sb = new StringBuilder();
    sb.Append("현재시간\r\n");
    sb.Append(DateTime.Now.Year.ToString() + "년");
    sb.AppendFormat("\r\n{0}월", DateTime.Now.Month);
    sb.AppendFormat("{0}{1}일 {2}""\r\n", DateTime.Now.Day, "\r\n");
    sb.AppendFormat("{0}시 {1}분 {2}초", DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second);
    this.textBox1.Text = sb.ToString();
}
 
private void timer1_Tick(object sender, EventArgs e)
{
    this.Form1_Load(nullnull);
}
cs

[코드 1]


[코드 1]을 보면 Form_Load 이벤트에서 DateTime의 형식을 지정해 textBox로 출력해준다.

그리고 Timer의 Tick 이벤트가 동작하면 Form_Load 이벤트를 동작시킨다.


Tick 이벤트는 Timer의 Interval 속성에 지정된 빈도값(밀리초)마다 동작한다. 1초는 1000밀리초다.

반응형



DateTimePicker는 날짜를 표시, 선택할 수 있게 만들어진 클래스다.


[그림 1]


[그림 2]


날짜와 시간을 표시하는 방식은 4가지로 나눌 수 있는데

Long , Short , Time , Custom 이 그것이다.


Long


1
this.dateTimePicker1.Format = DateTimePickerFormat.Long;
cs

[코드 1]

[코드 1]처럼 DateTimePicker의 Format 속성을 Long으로 설정해주면

[그림 3]

[그림 3]과 같이 년, 월, 일, 요일이 모두 표시된다.


Short


1
this.dateTimePicker1.Format = DateTimePickerFormat.Short;
cs

[코드 2]

마찬가지로 [코드 2]처럼 Format 속성을 Short로 설정해주면

[그림 4]

[그림 4]와 같이 년, 월, 일이 간단하게 표시된다.


Time


1
this.dateTimePicker1.Format = DateTimePickerFormat.Time;
cs

[코드 3]

Time은 단어에서 알 수 있듯 시간을 표시할 때 사용한다.

[그림 5]


Custom


1
2
3
this.dateTimePicker1.Format = DateTimePickerFormat.Custom;
//형식 지정
this.dateTimePicker1.CustomFormat = "yy년 MM월 dd일(ddd)";
cs

[코드 4]

Custom또한 이름에서 알 수 있듯이 표시될 형식을 직접 커스텀 할 때 사용한다.

[코드 4]와 같이Format 속성을 Custom으로 설정한 뒤 CustomFormat 속성을 따로 지정해 준다.

[그림 6]

[코드 4]에 CustomFormat 속성에 지정된 yy년 mm월 dd일(요일) 형식으로 [그림 6]에 표시된것을 볼 수 있다.

ddd는 요일을 가리키며 년도를 4자리로 표현하려면 "yyyy년"으로 쓰면 된다.




날짜 데이터를 원하는 형식으로 불러와 출력하려 할 경우

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private void button1_Click(object sender, EventArgs e)
        {
            string strMsg = String.Empty;
            switch (Flag)
            {
                case 1 :
                    strMsg = String.Format(
                "배송 예정일은 {0}입니다."this.dateTimePicker1.Value.ToLongDateString()); 
                    break;
                case 2 :
                    strMsg = String.Format(
                "배송 예정일은 {0}입니다."this.dateTimePicker1.Value.ToShortDateString()); 
                    break;
                case 3 :
                    strMsg = String.Format(
                "배송 예정일은 {0}입니다."this.dateTimePicker1.Value.ToLongTimeString()); 
                    break;
                case 4 :
                    strMsg = String.Format(
                "배송 예정일은 {0}년 {1}월 {2}일({3})입니다."this.dateTimePicker1.Value.Year, 
                        this.dateTimePicker1.Value.Month, this.dateTimePicker1.Value.Day, 
                        this.dateTimePicker1.Value.DayOfWeek); 
                    break;
            }
            MessageBox.Show(strMsg, "배송 예정일", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
cs

[코드 5]


[코드 5]와 같이 String으로 불러와 사용할 수 있다. 하지만 표시되는 Format 속성이 바뀌어도 Value 값에 영향을 주는건 아니기에 값을 불러올때의 형식을 따로 지정해줘야 한다.

Format 속성의 Long과 같은 형식으로 가져오려면 ToLongDateString()

Short와 같은 형식으로 가져오려면 ToShortDateString()

Time과 같은 형식으로 가져오려면 ToLongTimeString()으로 설정하면 되지만

Custom의 경우 맞는 형식이 따로 존재하지 않기에 [코드 5]와 같이 직접 설정해줘야 할 듯 싶다.

반응형

모달과 모달리스는 둘 다 우리가 컴퓨터를 이용하며 자주 접하던 기능이지만 이름만 들으면 이게 대체 뭐지? 하고 생각할 수 있다. 둘의 이름에서 서로 상반되는 기능을 할 것이라는건 추측할 수 있겠지만 이름만으론 무슨 기능을 할지 감이 잘 안잡히기 때문이다. 


모달, 모달리스는 윈도우에 Form이나 Dialog를 띄울 때 표시되는 방법 중 하나라 볼 수 있다.


모달(Modal)로 표시된 대화상자는 해당 대화상자가 종료되기 전에 그 대화상자를 띄운 애플리케이션으로 돌아갈 수 없는 대화상자를 의미한다. 반대로 모달리스(Modeless) 혹은 논 모달(Non-Modal)로 표시된 대화상자는 그 대화상자가 종료되지 않더라도 그 대화상자를 띄운 애플리케이션으로 돌아갈 수 있는 대화상자를 의미한다.


모달 대화상자는 현재의 대화상자가 종료되기 전엔 부모 단계로 돌아가지 못한다. 이것은 마치 반복문 내에 반복문이 또 하나 있을 때와 유사하다. 실제로 모달 대화상자를 생성하는 ShowDialog() 메서드는 Application.RunDialog()를 호출하여 새로운 메시지 루프를 생성한다. 기존 메인 스레드의 메인 루프에서 새로운 메시지 루프를 생성해 종료되기 전까진 메인 루프가 멈춰있는 것과 같은 효과를 내는것이라 생각한다.

모달리스 대화상자는 새로운 스레드를 생성하지도 새로운 메시지 루프를 생성하지도 않는다. 생성된 모달리스 대화상자는 부모폼과 Owner관계로 연결되며 메인 스레드의 메인 메시지 루프가 모달리스 대화상자를 처리하는 것이다.


프로그램 내에서의 동작을 생각해보면 순차지향적으로 동작하는 모달 대화상자가 설계하기에 쉬울것이라 짐작할 수 있다. 만약 데이터가 대화상자간 이동하는 상황에서 모달리스로 대화상자를 띄우면 데이터가 제대로 전달되지 못할 수 있기때문이다.


■모달 대화상자 띄우는 법


1
2
3
4
//Form2 인스턴스 생성
Form2 udf = new Form2();
 
udf.ShowDialog();//모달 폼
cs


■모달리스 대화상자 띄우는 법


1
2
3
4
//Form2 인스턴스 생성
Form2 udf = new Form2();
 
udf.Show();//모달리스 폼
cs


모달 대화상자는 애플리케이션 모달 대화상자와 시스템 모달 대화상자로 구분지을 수 있다. 


애플리케이션 모달 대화상자는 해당 대화상자를 띄운 애플리케이션으로는 돌아가지 못하지만 다른 애플리케이션으로는 돌아갈 수 있는 대화상자이다. 흔히 모달 대화상자의 예시로 볼 수 있는 도움말같은 정보를 보여줄 뿐인 messagebox같은 경우가 이에 속한다 할 수 있다.


시스템 모달 대화상자는 윈도우 운영체제에서 사용하는 대화상자로 치명적인 문제가 생겨 그 문제를 해결하지 않으면 더 이상 작업을 할 수 없을 때 사용된다.

반응형

그룹박스의 안에 만들어진 컨트롤에 접근하려면 Controls 메소드를 이용


groupBox.Controls[/*컨트롤의 인덱스 값*/]


와 같이 접근할 수 있다. 하지만 각 컨트롤이 몇번째 인덱스인지 햇갈릴 수 있는데 이 경우 Designer.cs에서 확인하면 된다.



예를 들어 위와같이 그룹 박스 안에 버튼 두개를 만들었다. 그리고 각 버튼의 Text값을 가져오려 한다.

그러려면 각 버튼이 그룹박스의 몇번째 컨트롤인지 확인해야 한다. Designer.cs의 groupBox에 대해 정의된 곳으로 가보면


1
2
3
4
5
6
7
8
9
10
11
// 
// groupBox1
// 
this.groupBox1.Controls.Add(this.방가워여);
this.groupBox1.Controls.Add(this.안뇽하세여);
this.groupBox1.Location = new System.Drawing.Point(4456);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(200100);
this.groupBox1.TabIndex = 0;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "그룹 박스";
cs


위와 같이 생성되어있다. 여기서 Controls.Add로 추가된 컨트롤들을 보자.

각 컨트롤의 인덱스 값이 몇인지는 나와있지 않지만 대충 코드가 순차적으로 진행된다는 것을 인지하면 가장 첫번째로 만나는 컨트롤에게 인덱스 0번이 부여될 것이라 추측해볼 수 있다.


컨트롤을 드래그 앤 드롭으로 그룹 박스 내에 생성시키면 Designer에는 자동으로 위로 쌓아가며 코드가 추가되기에 만약 별다른 수정을 거치지 않는다면 가장 마지막에 넣은 컨트롤이 인덱스 0번을 갖게 되는 것이다.


아래는 별다른 수정을 거치지 않고 컨트롤의 Text에 접근해 본 것이다.


1
2
3
4
5
6
7
8
9
private void 안뇽하세여_Click(object sender, EventArgs e)
{
    textBox1.Text = groupBox1.Controls[1].Text;
}
 
private void 방가워여_Click(object sender, EventArgs e)
{
    textBox1.Text = groupBox1.Controls[0].Text;
}
cs


마지막에 추가하여 groupBox1의 가장 위쪽에 정의된 "방가워여" 버튼이 Controls[0] 으로 접근 가능한 것을 볼 수 있다.

반응형

폼을 디자인 하던 중 현재 폼에서 다음 폼으로 넘어가는 동작을 구현해 보고 싶어져서 시도해 봤었다.


단순히 새로운 폼을 띄우는 방법은 간단하다. Form2라는 폼을 불러오고 싶으면 아래와 같이 해주면 된다.

1
2
3
Form2 showForm = new Form2();
 
showForm.Show();
cs


하지만 다음 폼을 띄워도 이전 폼이 남아있으면 다음으로 넘어간 느낌이 들지 않을테니 이전 폼을 꺼주는 동작을 추가해줘야 한다.  이를 위해 처음 사용해 본 방법은 Visible 속성을 이용한 방법이었다.



Visible 이용.


Visible 속성은 해당 컨트롤과 그 자식 컨트롤들을 표시해줄지를 설정하는 속성이다. 기본값은 true로 되어 있다.

말하자면 현재 켜져있는 폼의 Visible 속성을 false로 줌으로써 화면상에 표시되지 않도록 하고 다음 폼을 불러오는 것이다.

1
2
3
4
5
this.Visible = false;
 
Form3 showForm = new Form3();
 
showForm.Show();
cs


이렇게 하면 별 문제 없이 다음 폼으로 넘어가는 동작을 만들 수 있다. 

여기서 이전 폼으로 다시 돌아가는 동작을 하려면 두 폼간에 데이터 교환이 가능하거나 둘의 관계가 Owner 관계가 되어있으면 된다.


1
2
3
4
5
6
7
8
9



1
2
3
4
5
6
7
Form1.cs
 
Form2 frm = new Form2();
private void Next_button_Click(object sender, EventArgs e)
{
    this.Visible = false;
    frm.Owner = this;
    frm.Show();
}
 
 
 
Form2.cs
 
private void Back_button_Click(object sender, EventArgs e)
{
    this.Visible = false;
    Owner.Show();
}
cs


위와 같이 Form1에서 Form2 인스턴스를 생성시켜줄 때 Form2의 Owner 속성을 현재 폼을 가리키는 this로 주면 Form1에서 Form2를 소유하는 관계로 만들어진다. 그렇게 되면 Form2에서 이전 폼으로 돌아가는 동작을 할 때 자신의 Owner을 Show 시켜주는 것으로 간단히 이전 폼을 나타나게 할 수 있다.



Hide 이용.


같은 효과를 Hide 메소드를 이용해서도 줄 수 있다.

this.Visible = false부분만 아래와 같이 Hide로 바꿔주면 된다.


1
2
//this.Visible = false;
this.Hide();
cs



폼 종료 후 다음 폼 열기.


위 방법들을 사용해보다가 이번엔 이전의 폼은 종료시키고 다음 폼으로 넘어가버리는 동작을 구현해 보았다.


1
2
3
Form2 frm = new Form2();
frm.Show();
this.Close();
cs

Close로 Form1을 종료시키고 Form2로 넘어가는 동작이다. 하지만 이렇게만 해주면 Form1이 종료되면서 생성된 Form2도 함께 종료될 것이다. 그 이유는 Program.cs를 보면 조금 이해가 쉽다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace WindowsFormsApplication1
{
    static class Program
    {
        /// <summary>
        /// 해당 응용 프로그램의 주 진입점입니다.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}
cs


위 코드가 Program.cs의 내용이다. 위의 Main()을 보면 Application.Run(new Form1()); 라는 부분이 있다.

Form1을 메모리에 할당하여 윈도우 메시지 루프를 실행시켜주는 것이라 볼 수 있는데, 이 때 메모리에 할당된 Form1이 부모스레드로서 동작하고 Form2 등을 자식 스레드를 만들어 해결하고 있는 것이기에 Close로 Form1이 종료되면 생성되었던 Form2도 종료되어 버리는 것이다.


Form1이 할당된 메모리가 종료될 때 자동으로 Form2를 메모리에 할당시켜 주도록 하면 처음 폼이 꺼지면서 다음 폼을 켜주는 동작을 구현할 수 있다. 위의 Main()에 아래와같이 추가해주면 된다.

1
2
3
4
5
6
7
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new Form1());
    Application.Run(new Form2());
}
cs


이렇게 하면 별도로 Form1에서 Form2를 만들어 보여주는 동작을 하지 않아도 Form1이 Close되면 순차적으로 다음 코드Application.Run(new Form2()); 가 실행되며 Form2를 보여주게 된다.

반응형


폼(Form)?


폼이란 겉으로 드러나는 형태, 즉 사용자가 보게 되는 틀을 말한다. 
컴퓨터에서의 폼이라 하면 우리가 컴퓨터를 이용하며 흔히 접하게 되는 창들(ex | 메모장이나 윈도우 탐색기, 프로그램을 실행할 때 뜨는 창 등)을 통틀어 폼이라고 볼 수 있다. 윈도우 폼은 윈도우 운영체제에서 쓰이는 윈도우 API를 이용한 폼이라고 볼 수 있다.

윈도우 폼은 사용자가 직접적으로 보게되는 인터페이스이기에 사용자가 이용하기 편리하도록 실용적이고 멋있게 디자인 될 필요가 있을 것이다. 하지만 거기에서 끝나면 그냥 껍데기만 만들어진 것에 그친다. 그렇기에 각 부분에 컨트롤을 추가하여 이벤트가 발생할 시 처리할 수 있도록 만들어주면 윈폼 애플리케이션이 되는 것이다.

아래는 Visual Studio 2013을 이용해 간단한 윈폼 애플리케이션을 생성시켜 보는 과정이다.


위의 1 -> 2 -> 3 순으로 새 프로젝트를 생성시키면 아래와 같이 가장 기본적인 윈폼이 만들어진다.


옆의 솔루션 탐색기의 목록을 보면 Form1.cs 클래스 아래에 Designer와 Form1 총 2개의 클래스가 있는걸 볼 수 있다.

이는 코딩의 편의를 위해 Form1클래스를 partial을 이용해 부분클래스로 나눴기 때문인데 둘 중 개발자가 주로 다루게 될 부분은 Form1의 내용이다. Designer에는 폼의 디자인 및 속성과 관련한 코드가 들어가는데 이 코드는 개발자가 직접 추가할 수도 있지만 도구상자나 속성창을 이용해 변경하는 값들이 자동으로 추가되기 때문에 미세한 조정 이외에는 굳이 손댈일이 적기 때문이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
namespace WindowsFormsApplication17
{
    partial class Form1
    {
        /// <summary>
        /// 필수 디자이너 변수입니다.
        /// </summary>
        private System.ComponentModel.IContainer components = null;
 
        /// <summary>
        /// 사용 중인 모든 리소스를 정리합니다.
        /// </summary>
        /// <param name="disposing">관리되는 리소스를 삭제해야 하면 true이고, 그렇지 않으면 false입니다.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
 
        #region Windows Form 디자이너에서 생성한 코드
 
        /// <summary>
        /// 디자이너 지원에 필요한 메서드입니다.
        /// 이 메서드의 내용을 코드 편집기로 수정하지 마십시오.
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.Text = "Form1";
        }
 
        #endregion
    }
}
 
 
cs

<기본적으로 만들어지는 Designer의 내용>


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace WindowsFormsApplication17
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
    }
}
 
cs

<기본적으로 만들어지는 Form1의 내용>


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace WindowsFormsApplication17
{
    static class Program
    {
        /// <summary>
        /// 해당 응용 프로그램의 주 진입점입니다.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}
 
cs

<기본적으로 만들어지는 Program.cs의 내용>


위 3개가 각 클래스 3개에 자동으로 생성되는 코드다. 

코드를 보면 Program.cs에 응용 프로그램의 시작점인 Main메소드가 있다. Application 클래스의 Run메소드에 윈도우 폼 클래스의 인스턴스를 매개변수로 넘겨주어 호출하면 Main스레드에서 윈도우 메시지 루프를 시작하고 지정된 폼을 보여주게 된다.


Form1클래스 안에 public Form1(){}은 생성자의 역할을 한다. 클래스가 생성될 때 자동으로 실행되는 부분인데 안에 보면 InitializeComponent();가 추가되어 있다. 이는 Designer 클래스에서 찾아볼 수 있는데 폼의 디자인이나 컨트롤 정의들이 모두 이 안에 정의되어 생성된다. 말하자면 폼의 디자인, 컨트롤 등을 초기화 해주는 작업이라 볼 수 있다.


폼의 디자인은 도구상자에 등록되어 있는 각 객체(도구들은 모두 클래스로 만들어져 있다.)들을 드래그 앤 드롭으로 쉽게 디자인 할 수 있게 만들어져 있지만 좀더 세세한 내부 과정을 보고 싶으면 드래그 앤 드롭으로 만들 시 Designer 클래스에 자동으로 추가되는 내용들의 변화를 살펴보며 해보면 도움이 될 듯 하다.


<오른쪽 Form1.cs[디자인]의 폼을 클릭 후 도구 상자를 열면 여러 도구가 나타난다>


반응형

+ Recent posts