치지직 방송을 대기하다가 방송이 켜졌을 때

자동으로 브라우저를 열어 해당 방송을 켜주는 프로그램을 만들어 테스트를 해보던 도중

아래와 같은 에러에 부딪혔다

막 on된 방송에 들어갈 때 이따금 볼 수 있는 에러

정확히는 프로그램상의 에러는 아니고 치지직에서 막 켜진 방송들이 이따금 에러를 뱉어내다 잠시 후 정상 송출되는 에러다.

문제는 그냥 api를 체크해서 방송의 status가 바뀌었을 때 브라우저를 켜주는 동작만 했더니

위와같은 에러가 뜨면 수동으로 새로고침이라도 해줘야 한다는 점이다.

 

그래서 어떤 부분의 문제인지 테스트를 좀 해봤다. 일단 영상 자체를 불러오지 못하는 문제인가 싶어

방송의 status값이 바뀐 후에도 해당 채널 id값의 media hls값을 제대로 받아오는지 확인한 후

정상적으로 받아올 때 브라우저를 켜주는 식으로 수정하여 실행을 시켜봤다.

 

테스트 실행을 해보니 에러가 날 상황엔 hls 체크를 지속적으로 하다가 정상적인 상태일 때 잘 켜지는 듯 했는데,

오늘 새로 테스트 해보니 다시 에러상태일 때 창이 켜지는 상황이 확인되어 수정을 들어갔다.

 

live-detail 상에 hls주소가 업데이트 된 직후 시간을 주지 않고 바로 창이 켜져서 생긴 문제일 수도 있으나,

그 부분까진 아직 테스트를 해보지 못했다. 위에 말했듯 치지직 상 이따금 생기는 에러라 원할때마다 문제 상황을 재현해보지 못하고 있기 때문

 

일단 해당 에러가 난 페이지를 정상적으로 방송이 송출중인 페이지와 엘리먼트를 비교해보니 

에러상황
정상동작

저렇게 표시해둔 부분에서 차이가 발견되었다. 정상 송출 중에는 src 값을 받아오고 있는 듯 하다. 그래서 해당 값이 어디에서 업데이트 되고 있는지 디버깅 해보았으나..

 

이쪽은 보고있어도 잘 모르것다..

 

일단 이 부분은 놔두고 차선책으로 파이썬에 Selenium을 사용해서 해당 엘리먼트의 src 속성 값을 읽고, 값이 있는지 여부를 확인하는 방법을 취해보거나, 아니면 해당 에러 상황에서 live-detail api 창을 한번 실행시켜서 정보값을 받아온 뒤 해당 값과 이후 정상 송출시의 값에 어떤 차이가 있는지 한번 비교를 해보는 것도 좋을 것 같다.

 

전에 수동으로 live-detail 을 켜서 비교해본 적이 있긴 하지만 그때는 수동이라 속도가 늦기도 했고 문자 비교로 조금만 확인 해봤던거라 확실하지 않다.

 


에러 상황에서의 live-detail 값을 받아와봤다.

같은 값이 나오는 부분은 제외하고 livePlaybackJson 내부의 값에 차이가 확실히 보인다.

에러상황

 

정상

그런데 이미 다르게 나올것은 예상 하던 부분이기도 하다. 기존에 에러상황을 체크하기 위해 mediaID : HLS의 path값이 있는지 확인하는 로직이 있었고 에러상황의 로그 확인중에 이미 이 값이 없다고 여러번 띄웠던 적이 있었기 때문.

문제는 hls의 path 값까지 정상적으로 존재함을 확인 한 후에 열렸던 창에서도 에러가 나왔던 적이 한번 있었는데

그 상황을 다시 재현해보지 못하면 쉽게 알기 어려울 듯 하다.

같은 창의 브라우저 내에서 짧은 시간 간격으로 새 탭에 열리면서 무언가 꼬였을 가능성도 존재하지만 확실한 부분은 없는 상태

사전의 체크로 정확한 구분이 어려우면 그냥 후속적인 체크를 추가하는게 좋긴 하겠다만 일단 테스트 가능한 부분까진 해볼생각

반응형

'IT > buglog' 카테고리의 다른 글

[Unity] 애니메이션 동작 문제..  (0) 2025.03.16

점프 애니메이션 동작에 미묘한 이상 동작이 자꾸 생겨서 문제를 살펴보니 두가지 정도의 문제가 확인 됨

 

우선 하나는 Add.Force로 플레이어를 움직여 주는 현 상태에서

오브젝트가 땅에 착지하는 순간 바로 다시 점프를 수행 했을 때

플레이어의 velocity.y의 값이 즉각적으로 증가하지 않으면서 생기는 문제

정상 동작시 로그
비 정상 동작시 로그

문제는 Add.Force로 움직이는 오브젝트가 관성에 영향을 받아서인 것으로 추정된다.

해결해주기 위해 Add.Force로 값을 주기 직전 기존의 velocity의 값을 0으로 초기화 시켜주는 작업을 추가했다.

...
// 관성 초기화를 위해 움직임 강제 초기화
rb.velocity = Vector3.zero;
// Rigidbody에 힘 적용
rb.AddForce(launchForce, ForceMode.Impulse);
...

일단은 정상 동작 하는 것으로 보임

 


두 번째 문제로는

점프에 대해 settrigger 해주는 부분에 뭔가 이상한 동작을 확인

 

코드 동작 상에서 Settigger는 한번만 시켜주고 실제로 로그 출력 상에서도

Settigger 부분은 한번만 동작 하는게 확인 되었는데

 

애니메이션이 간헐적으로 이상하게 동작하는 때에만 trigger의 bool 값을

GetBool로 확인해보니 true의 값이 연속적으로 나온다

정상 동작일때 (1이 Settigger 동작시 출력되고 True가 Getbool로 가져온 trigger의 상태값이다)
비 정상 동작 ( 1이 한번만 출력된걸 보면 Settrigger는 한번만 호출된 것이 맞는데 trigger의 상태값은 바로 꺼지지 않고 true로 지속된 것이 확인된다)

 

아래처럼 동작 순서를 조정해서 다음 프레임에도 GetBool로 tigger의 값이 true면 로그값이 출력하게 해보니

문제가 생기는 경우에만 로그가 나오는걸 봐선 정상 동작 시 trigger의 값은 첫 프레임에만 켜진 후

다음 프레임엔 false로 꺼지는게 맞는 듯 한데 이게 바로 꺼지지 않아서 생기는 문제인 듯 하다.

 

Update()
{
	...
    if(animator.GetBool("doJump")
    {
    	Debug.Log("test");
    }
    if( .. )
    {
    	animator.SetTrigger("doJump");
    }
    ...
}

 

 

근본적인 해결책이라 보긴 어렵지만 아래와 같이 해서 고쳐봤다. 일단은 문제없이 동작 하는 듯 한데 경과를 더 지켜봐야 할 듯

if (anim.GetBool("doJump"))
{
    anim.ResetTrigger("doJump"); //trigger 초기화
    anim.Play("Jump", 0, 0f); //Jump 애니메이션 강제 실행
}

 

반응형

'IT > buglog' 카테고리의 다른 글

치지직 방송 처음 시작 시 에러  (0) 2025.04.27

한번에 여러개의 반복되는 파일 이름을 바꾸고자 할 때

윈도우 파워쉘에서 명령어로 수행 가능하다.

 

파일들이 있는 폴더에서 파워쉘을 킨 후

 

해당 폴더에서 shift+우클릭을 하면 여기에 PowerShell 창 열기가 있다

 

 

Get-Childitem "바꿀 대상" | ForEach-Object {Rename-Item $_.FullName -NewName($_.Name -replace "원래 이름", "바꿀 이름")}

을 하면 바뀐다.

 

예를 들어

이렇게 하면 폴더 내의 모든 .txt파일에서 aaaa로 된 단어를 bbbb로 바꾼다.

결과물..

 

좀 더 세부적으로 바꾸고 싶으면 정규식 등을 이용해도 좋다.

 

만약 폴더 내의 .txt파일을 이름이 뭐든 상관없이 test0부터 숫자가 증가하는 식으로 만들고 싶다면

이런식으로도 쓸 수 있다.

(정규식에 .+가 아니라 \w+를 쓰면 글자 하나하나를 test.txt로 바꿔버린다..)

결과물..

 

반응형


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] 으로 접근 가능한 것을 볼 수 있다.

반응형

+ Recent posts