2014.10.24 09:47

C# 윈폼에서 창 열고 닫는 소스코드 입니다.


단순히 .Show()만 하면 되지 않느냐구요??

(직접 겪어보시믄 이게 왜 필요한지 알게 됩니다잉~)


여기서 ntcDF는 Form객체 입니다.



창 열기

        private void showNotice()
        {

            if(!ntcDF.Created)
            {
                if(ntcDF.IsDisposed)
                {
                    ntcDF = new NoticeDF();
                }

                ntcDF.Show();
            }
            else
            {
                ntcDF.Activate();
            }
        }



창 닫기

        private void closeNotice()
        {
            if(!(ntcDF == null))
            {
                ntcDF.Close();
            }
        }  




Posted by 해비
2014.10.15 17:19


컬럼(Column) 잠그기

this.fpSpread1_Sheet1.Columns.Get(0).Locked = true;
this.fpSpread1_Sheet1.Columns.Get(1).Locked = true;
this.fpSpread1_Sheet1.Columns.Get(2).Locked = true;




컬럼(Column) 정렬기능 추가

1

 this.fpSpread1.ActiveSheet.SetColumnAllowAutoSort(-1, true);

2

 this.fpSpread1.Sheets[0].Columns[1].AllowAutoSort = true;

- Column 헤더 클릭 시 해당 Column 기준으로 데이터를 정렬하여 표시 해 준다.

- [1] 또는 [2] 중 한가지를 선택 적용한다.



현재 선택한 Row 색칠하기(잠겨진 셀 포함)

//잠긴 셀에 지정된 색상 해제
fpSpread1.ActiveSheet.LockBackColor = Color.Empty;

//기존에 칠된것 모두 제거
for(int i=0; i<fpSpread1.ActiveSheet.Rows.Count; i++)
{
    fpSpread1.ActiveSheet.Rows[i].BackColor = Color.Empty;
}

//새로 색칠
fpSpread1.ActiveSheet.Rows[iCurRow].BackColor = Color.FromArgb(255, 255, 0);

- RGB색상은 마음에 드는 색상으로 설정한다.




싱글 선택만 되도록

this.fpSpread1_Sheet1.SelectionPolicy = FarPoint.Win.Spread.Model.SelectionPolicy.Single;

- 디자이너 화면에서 설정 가능하다.




셀 한번 클릭 시 이벤트

private void fpSpread1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{

}

- CellClick 이벤트는 이전 클릭된 것을 바라보는 문제가 있고, SelectionChange 이벤트는 1개뿐이 없을 때 다시 선택해도 이벤트 발생이 되지 않는 문제가 있다.(이건 당연하지만...)


- DoubleClick 이벤트는 말 그대로 두번 클릭질 해야 하는데 역시 불편하다. 두번클릭보단 한번클릭이 아무래도 더 편하니까~~


혹시 다른 또는 더 좋은 방법 있으면 한 수 가르침 부탁드립니다.




컬럼 헤더 셋팅 예제코드

fpSpread1.Sheets[0].ColumnHeader.Cells[0, 0].Text = "코드";
fpSpread1.Sheets[0].Columns[0].Width = 60;
fpSpread1.Sheets[0].ColumnHeader.Cells[0, 1].Text = "내용";
fpSpread1.Sheets[0].Columns[1].Width = 60;
fpSpread1.Sheets[0].ColumnHeader.Cells[0, 2].Text = "설명";
fpSpread1.Sheets[0].Columns[2].Width = 250;

- 컬럼 헤더 타이틀, 컬럼의 가로길이 설정 예.




멀티라인 텍스트 데이터 가져오기

private DataTable _rtnDT; // 전역변수 선언


// 스프레드에 데이터 바인딩

_rtnDT = _controller.getData();

fpSpread1.DataSource = _rtnDT;


// 스프레드 내용 참조 시

iRow = fpSpread1.ActiveSheet.ActiveRowIndex;


txtProhAbbr.Text = _rtnDT.Rows[iRow][0].ToString();
txtProhMemo.Text = _rtnDT.Rows[iRow][1].ToString();

- fpSpread의 [row,col].Text 로는 멀티라인 데이터를 텍스트 박스에 연결 시 한줄로 출력되는 문제가 있어 해당 Row번호만 알아낸 다음 DataTable에서 직접 가져온다.

혹시 다른 또는 더 좋은 방법 있으면 한 수 가르침 부탁드립니다.




셀 병합

fpSpread1.Sheets[0].AddSpanCell(0, 0, 2, 1);

- 인자 4개를 넘겨줘야하는데 앞 2개 인자는 병합 시작 셀의 row, col 값 이고, 뒤에 2개 인자는 병합할 row 수, 병합할 col 수 이다.

- 위 예제를 본다면 0,0 으로 부터 2개 Row, 1개 Col 병합 이므로 아래와 같이 될 것이다.


 

 


0,0 좌표로 부터 2개 Row 병합된 상태, Col 은 1 이었으므로 병합되지 않는다. 만약 Col 도 2 였다면, 2 x 2 셀 모두 합쳐 진다.




엑셀 내보내기

// 스프레드에 내보낼 정보 적재
fpSpread1.DataSource = rtnDS.Tables[0];

// 컬럼길이 조정
fpSpread1.Sheets[0].Columns[0].Width = 70;  // 사번
fpSpread1.Sheets[0].Columns[1].Width = 70;  // 성명
fpSpread1.Sheets[0].Columns[2].Width = 50;  // 삭제

// 파일저장 다이얼로그 확장자 필터 설정
savedlg.Filter = "Excel files (*.xls)|*.xls|All files (*.*)|*.*";
savedlg.FilterIndex = 1;

if (savedlg.ShowDialog() == DialogResult.OK)
{
    // 스프레드의 내용을 엑셀파일로 저장
    fpSpread1.SaveExcel(savedlg.FileName, FarPoint.Win.Spread.Model.IncludeHeaders.ColumnHeadersCustomOnly);

    MessageBox.Show("저장이 완료 되었습니다.", this.Text,
        MessageBoxButtons.OK, MessageBoxIcon.Information);
}

- SaveFileDialog 컨트롤 을 호출하여 저장할 위치, 파일명을 입력받고, 스프레드의 내용을 해당 위치에 내보낸다.

- 스프레드 속성 중 Visible = false 인 경우, 시트 없는 빈 엑셀 파일이 생성되므로 주의한다.






Posted by 해비
2014.04.24 09:40

다룰 내용...

1. 날짜 형식 변수 선언 및 날짜 데이터 입력

2. 두 날짜 From ~ To 사이의 일수 계산


// 1. Date형식의 변수에 날짜를 설정

DateTime FrDate = DateTime.ParseExact("20140422", "yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture); // 시작

DateTime ToDate = DateTime.ParseExact("20140521", "yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture); // 종료


// 2. 두 날짜 사이의 일수

TimeSpan ts1 = ToDate - FrDate;  // 2014년 5월 21일 - 2014년 4월 22일 = 29일 (+1로 보정해야 한다)


// 보정하고 정수형 변수에 담는다.

int Days = ts1.Days +1;


// 끝~~


+1 해주는 이유는...

예를 들어 1일 부터 3일 까지의 기간으로 했을 때, 실제로는 1일, 2일, 3일 이렇게 총 3일 이다.

하지만 날짜 계산에서 3 - 1 = 2가 되므로 시작일 하루를 가산하여 보정해 줘야 한다.


시작일 가산...? 다른 표현 방법이 떠오르진 않지만 여튼 뭐 그렇다.




더 좋은 방법 및 의견 코멘트 환영합니다.  ^__^


Posted by 해비
2013.12.05 18:07

조금 특이한 케이스를 잡아서 소개합니다.

데이터셋과 콤보박스가 연결된 상태에서 발생하는 문제입니다.


해당 문제를 재현한 프로그램 

환경 : C#.NET 1.0 WinForm

상황 : ComboBox 컨트롤의 값을 코딩으로 변경하였는데 변경된 값이 실제로 반영되지 않는 문제.


WindowsApplication2.rar

(실행파일 & 소스 포함, C#. Net 1.0, VS .NET 2003 에서 컴파일 되었습니다.)



[[ 문제 상황 ]]

1. 콤보박스(ComboBox) 목록 등록

콤보박스(ComboBox)의 목록은 ValueMember, DisplayMember 속성을 테이블의 컬럼으로 지정 후, DataSource 속성에 테이블을 지정하는 방법으로 한다.


2. 실제 코드값(데이터)를 가져온 데이터셋이 필요


3. DataBingings 속성으로 2의 실제 코드값을 바인딩 처리


4. 코드상에서 콤보박스 값을 변경 후 데이터셋 값 확인



여기서 콤보박스의 SelectedValue 속성을 통해 값을 변경 하면, 화면에는 바뀐 값이 표시되나, 실제 데이터셋의 값은 처음 가져온 상태 그대로 변동이 없으므로 주의가 필요합니다.


1. 마우스로 콤보박스를 직접 선택하여 값을 변경하게 되면 변경된 값이 2항에 데이터셋에도 같이 변경되어집니다.

    마우스로 직접 건드리는 경우에는 데이터셋의 값이 함께 변경되어 지는 것을 확인 할 수 있습니다.

2. 마찬가지로 데이터셋을 직접 건드리면 바뀐 값이 콤보박스에도 그대로 반영됩니다.

3. 마우스로 직접 건들고 난 이후에는 데이터셋을 변경 하여도 콤보박스의 값이 바뀌어 지지 않습니다. 


즉, 데이터바인딩 된 개체의 값을 소스로 핸들링 시 컨트롤을 건들지 말고, 바인딩된 해당 데이터셋의 값을 고쳐야 한다는 것

(왜 그런지에 대한 이유는 모르겠습니다. 어쨋든 되는 방향 찾았으니 그걸로 또 하나의 삽질을 끝냅니다.)



혹, 원인 이라던가 좀 자세한 내용을 알고 계신분은 한수 가르쳐 주시면 감사하겠습니다 (__)



[2013/12/06]

정정합니다.

.Net 1.0 이 아닌 환경에서는 해당 문제가 발생하지 않는 것으로 보아 프레임워크 버그인듯 합니다.

.Net 4.5 Framework 만 설치된 컴퓨터에서 프로그램 실행시 증상이 나타나지 않는 것을 확인하였습니다.



Posted by 해비
2010.05.25 14:26

 이번에는 아~~주 복잡한 패스워 드를 자동으로 생성해주는...
(그래봤자 그냥 임의로 나열하는 문자열 되겠습니다 만은...)

CRP(Create Random Passwords) 입니다.
랜덤한 패스워드 생성? 정도가 되겠네요;;;

프로그램 실행을 위해서는 .Net framework 2.0 이 컴퓨터에 설치되어 있어야 합니다.




소스코드는 압축파일내에 들어있으며, 주석까지 달려 있어서 이해하는데 그리 어렵지는 않을 것입니다.


[구동설명]

1. 랜덤함수로 임의의 숫자를 생성한다음

2. 그 숫자에 대응하는 각각의 문자를 출력하도록 하였습니다.

3. 문자는 아스키 코드값을 그에 해당하는 문자출력하는 방식으로 만들어졌습니다.


[주석이 포함된 소스코드 및 실행파일]





Posted by 해비
2010.02.03 20:28

나름 간단하게? 구현해본 백트래킹 (맞는지는 잘 모르겠으나 어쨋든 백트래킹으로 명명)입니다.

입력받은 배열의 값에 대해서 가능한 모든 순서조합을 만들어냅니다.
단, 모든 순서조합을 위해서는 최초에 배열의 수가 오름차순으로 정렬되어져 있어야 합니다.

최종적인 형태는 내림차순정렬이 되어져 있으며, 이때 함수는 더이상 처리를 하지 않고 들어온 값 그대로 리턴 시켜 버립니다.

내림차순 정렬이 완료 되었으나, 맞는 조합이 없었다면, 해당 문제는 해가 없는 것이 됩니다. (즉, 풀수 없는 문제...)

매번 시도 마다 다음 조합으로 만들어 냅니다. (1차 배열만, 배열의 크기는 무관)
현재 배열의 순서가 답이 될수 없다면, 배열을 다시 백트랙 돌리면 바로 다음 배열 순서의 조합을 만들어냅니다.

1-2-3-4-5-6-7-8-9 의 항이 있었다고 가정할 때...
이 값의 순서가 해당 문제의 답으로서 맞지 않는다면 다음 항으로는
한칸 앞으로 돌아와서(이것이 백트랙이죠)
순서를 바꾸어 볼수 있습니다.
따라서,
1-2-3-4-5-6-7-9-8 을 생각해 볼수 있습니다.

그리고 몇번만 시도를 해보자면...
1-2-3-4-5-6-8-7-9
1-2-3-4-5-6-8-9-7
1-2-3-4-5-6-9-7-8
1-2-3-4-5-6-9-8-7
1-2-3-4-5-7-6-8-9
(...)
9-8-7-6-5-4-3-1-2
9-8-7-6-5-4-3-2-1 (최종값)

예) Array = BackTrack(Array)
(* Array는 1차 배열 변수)

아래 그림은 배열에 현재 값이 {6,7,3,5,4,2,1}이 들어있을 때, 함수 내부에서 다음 배열의 순서인 {6,7,4,1,2,3,5} 로 바뀌는 과정을 설명합니다.


소스코드입니다.
        // ===============================================================================================
        // BackTrack()
        // 제작자 : haebi.kr
        // 작성일 : 2010-02-03
        // 수  정 : 2010-02-03
        // 내  용 : 실행시, 배열에서 모든 나열 방법을 계산하여 매 경우를 순서대로 나열
        //          인자로 배열을 넘겨받고, 결과를 배열로 리턴
        //          최종적인 형태는 배열의 내림차순 정렬
        // ===============================================================================================

        private int[] BackTrack(int[] Array)
        {
            // 백트랙에서 최종적으로 증가된 위치 값을 기억
            int BT_LTop = ArrLTop(Array);
            // 배열에서 마지막으로 증가한 위치의 값을 기억
            int SU_tmp1=0;

            // 1. 배열에서 마지막 증가위치가 배열의 끝 일때...
            if (BT_LTop == Array.Length - 1)
            {
                // 마지막 증가위치
                Array = ArrSwitch(Array, BT_LTop, BT_LTop - 1);
            }
            // 2. 마지막 증가위치의 값 바로 앞의 수를 다음 수로 바꾼뒤 뒷부분 정렬
            else
            {
                //마지막 증가값의 위치 앞부분이 -1 이 아닐때...
                if (BT_LTop - 1 != -1)
                {
                    // 2-1. 마지막 증가위치 바로 앞의 값을 임시 변수에 저장
                    SU_tmp1 = Array[BT_LTop - 1];
                    // 2-2. 마지막 증가위치 바로 앞부분으로 부터 뒷부분 정렬
                    Array = ArrSort(Array, BT_LTop - 1);
                    // 2-3. 마지막 증가위치 바로 앞부분부터 뒤로 스캔하여 다음으로 큰값 찾아서 스위칭
                    Array = ArrSwitch(Array, BT_LTop - 1, ArrNext(Array, BT_LTop - 1, SU_tmp1));
                    // 2-4. 마지막 증가위치로 부터 뒤로 다시 오름차순 정렬
                    Array = ArrSort(Array, BT_LTop);
                }
                else
                {
                    return Array;
                }
            }
            return Array;
        }


백트래킹 함수의 소스는 여기까지 입니다만, 이 함수의 내부에서 쓰여진 함수들 또한 별도로 만들어야 합니다.
- ArrLTop()
- ArrSwitch()
- ArrSort()
- ArrNext()


--------------------------------(여기부터 내부에서 쓰인 함수들)------------------------------------------

        // ===============================================================================================
        // ArrLTop()
        // 제작자 : haebi.kr
        // 작성일 : 2010-02-03
        // 수  정 : 2010-02-03
        // 내  용 : 배열에서 마지막으로 값의 변화가 증가된 곳을 리턴
        // ===============================================================================================
        private int ArrLTop(int[] Array)
        {
            int i=0;
            int LTop=0;

            for (i = 0; i < Array.Length - 1; i++)
            {
                if (Array[i] < Array[i + 1])      // 바로 다음 배열의 값이 현재 값 보다 큰지 체크!
                {
                    LTop = i + 1;                 // LTop 가장마지막에 이전값과 비교해 증가한 값의 배열 위치 갱신
                }
            }
            return LTop;
        }



        // ===============================================================================================
        // ArrSwitch()
        // 제작자 : haebi.kr
        // 작성일 : 2010-02-03
        // 수  정 : 2010-02-03
        // 내  용 : 배열에서 Value1과 Value2의 위치에 있는 값을 교환
        // ===============================================================================================
        private int[] ArrSwitch(int[] Array, int Value1, int Value2)
        {
            int tmp;
            tmp = Array[Value1];
            Array[Value1] = Array[Value2];
            Array[Value2] = tmp;
            return Array;
        }



        // ===============================================================================================
        // ArrSort()
        // 제작자 : haebi.kr
        // 작성일 : 2010-02-03
        // 수  정 : 2010-02-03
        // 내  용 : 배열에서 Pos위치 부터 뒤로 오름차순 정렬
        //          (버블소트 알고리즘 응용)
        // ===============================================================================================

        private int[] ArrSort(int[] Array, int Pos)
        {
            int i = 0;
            int j = 0;
            int icnt = 0;

            // --------------------------------------------------
            // 버블소트 알고리즘 (선택범위 정렬)
            // --------------------------------------------------
            for (i = Pos; i < Array.Length - 1; i++)
            {
                for (j = Pos; j < Array.Length - 1 - icnt; j++)
                {
                    if (Array[j] > Array[j + 1])
                    {
                        Array = ArrSwitch(Array, j, j + 1);
                    }
                }
                icnt++;
            }
            // --------------------------------------------------
            return Array;
        }



        // ===============================================================================================
        // ArrNext()
        // 제작자 : haebi.kr
        // 작성일 : 2010-02-03
        // 수  정 : 2010-02-03
        // 내  용 : 배열에서 시작위치(stPos)부터 뒤로 스캔하여 입력값(Num)보다 바로 다음으로 큰수를 리턴
        // ===============================================================================================
        private int ArrNext(int[] Array, int stPos, int Num)
        {
            int i = 0;
            byte detect = 0;
            // 입력받은 배열을 tmpArray에 복사
            int[] tmpArray = (int[])Array.Clone();
            // stPos 으로 부터 뒷부분 정렬
            tmpArray = ArrSort(tmpArray, stPos);

            for (i = stPos; i < tmpArray.Length; i++)
            {
                // 바로 같은 값이 발견된 상태이면
                if (detect == 1)
                {
                    // 배열에 같은값이 존재 할 경우...
                    if (tmpArray[i] == Num)
                    {
                        detect = 0; // 발견 플래그 초기화
                    }
                    else
                    {
                        return i; //바로 다음 항목 출력
                    }
                }

                // 입력받은값과 배열의 값이 같은경우
                if (Num == tmpArray[i])
                {
                    detect++; // 발견 플래그 설정
                }
            }
            return -1;
        }


Posted by 해비
2010.02.01 23:56


C# 으로 만든 초간단 팩토리얼 함수 입니다.
인자로 INT값을 하나 받으면 리턴값 또한 INT입니다.

        // ----------------------------------------------------------------------
        // 팩토리얼 함수
        // 1*2*3* ... *n
        // ----------------------------------------------------------------------
        private int Factorial(int Num)
        {
            if (Num == 0)               // 입력된 값이 0 이면 0을 리턴
            {
                return 0;
            }

            int i=1;
            int Fac_Value=1;

            for (i = 1; i <= Num; i++)  // 1부터 입력받은 수 까지 반복
            {
                Fac_Value *= i;         // Fac_Value에 반복카운트의 수를 계속 곱함
            }
            return Fac_Value;           // 반복이 끝나면 곱한 수의 결과값을 리턴
        }
        // ----------------------------------------------------------------------

Posted by 해비
2010.01.27 18:24


ThreadEx1의 개량형 버젼입니다.

기존에는 반복횟수를 카운트 하는 쓰레드 에서 표시까지 직접하였었는데, 컨트롤에 텍스트 표시하는데 걸리는 CPU의 부하 라던가 시간을 생각하다가 그냥 반복만 돌면 스피드가 얼마나 나올까 하는 생각에 제외시키기로 해보았습니다.

하지만 반복이 끝나기까지 마냥 기다리려면 좀 답답한 감이 있으니... 별도로 쓰레드를 생성하여 반복루프를 도는 작업쓰레드의 진행상황을 표시해 주는것으로 짜 보았습니다.

실제로 루프 카운트 는 AA() 에서 올라가고, BB()는 AA()의 현재 진행상황을 비동기로 알려주고 있습니다.

예상했던 대로 엄청난 스피드를 보여주더군요^^


120000000 번의 반복을 10초도 안걸려서 끝내버렸습니다.
(Core 2 Duo T7300, 4GB DDR2, Win7, .NET2.0)

쓰레드2의 반복(표시)횟수는 쓰레드1과 동기화를 하지 않고 있으며, 쓰레드1이 끝날 때 같이 끝나게 되어있으므로 매번 카운트 횟수는 다르게 나옵니다.


기존에는 모든 반복카운트에 표시를 해주었다면...

이번에는 중간중간 빼먹어 가면서 표시를 해 주고 있다고 보면 됩니다.

 



 

Posted by 해비
2009.10.01 12:47

개발환경
- Visual Studio 2005 (SP1)
- Windows Vista Home Premium K (32-bit)




폼 디자인...
뭐 특별한건 없고 그냥 간단간단 설정좀 했습니다.
textBox1 만 있고 나머지는 그냥 배치만...

그림에 빠졌는데 반복횟수란 글자는 레이블(Label) 컨트롤 배치해 놓은것 입니다.


윗 부분에 쓰레드 사용을 위한 네임 스페이스를 지정해 줍니다.


Form1 클래스의 상단에 프로그램 전체에서 사용될 변수를 선언해 줍니다.
여기서는 쓰레드 3개를 사용하는 것으로 합니다.


Form을 더블클릭 하면 폼의 로드 이벤트로 넘어갑니다.
여기서 반복 횟수 입력 상자에 디폴트로 지정된 반복 횟수(th_Count)를 출력해 줍니다.

textBox1 에 실제로 내용을 출력해 주는 부분입니다.
쓰레드 내에서 이 함수에 값을 넘기면, textBox1에 내용을 추가하고 줄 바꿈 하는 형식으로 되어있습니다.

쓰레드가 반복횟수를 다 채우게 되면 하게 될 작업 입니다.

디자인 폼에서 button1 을 더블클릭 하면 button1의 클릭 이벤트로 넘어옵니다.
여기서 기본적인 셋팅과 함께 각 쓰레드들을 시작 시키는 일을 합니다.

- 현재의 반복횟수를 나타내는 변수 i 를 0으로 초기화 시킵니다.
- th_Count(반복횟수 지정)변수에 textBox2 에 입력된 숫자값을 입력합니다. (문자이면 ?)
- textBox1 을 클리어 시킵니다. (이전에 동작된 내용을 삭제)
- 쓰레드 동작중에 쓰레드 시작을 하게되는 button1 과 반복횟수 입력 되는 textBox2 를 건드리지 못하도록 Disable 시킵니다.

* textBox2 에 문자값이 들어가더라도 걱정할 이유는 없습니다.
소스코드에 보면 button1_Click 이벤트의 제일 첫 줄에 try 가 쓰이고 있습니다.
기본적인 형태는
try
{
//작업내용...
}
catch { }
입니다.

try 구문에 있는 작업 내용을 실행하되, 중간에 오류가 발생하면 그 시점에서 catch 구문으로 던져버립니다.
그런데 catch 에서 할 내용은 아무것도 없이 비워놓았으니 그냥 끝나버리게 됩니다.
만약 try catch 없이 그냥 본 내용이 들어갔을 경우, 문자값이 textBox2에 들어가면 뭔가 오류 메시지 박스가 뜨겠지요;;

경우에 따라서 try catch 에서 catch 구문에 친절하게 오류발생시 작업내용(오류 알림 상자... 등)을 작업하여도 됩니다.

쓰레드 th1, th2, th3 에서 수행할  AA(), BB(), CC() 입니다.
내용은 같습니다.
다만 출력할 때, 어느 쓰레드에서 작업한 내용인가를 알려주기 위한 문자값과, 쓰레드 시작 플래그 값만 조금 다를 뿐입니다.

- 일단 쓰레드가 시작되면 i의 값을 1 증가 시킵니다.
- 그리고 문자형 변수에 i의 값을 기록하고
- sPrint 함수에 현재 쓰레드를 알려줄 문자와 함께, 그 값을 던져 textBox1 에 출력 되게 합니다.
- i 의 값이 반복횟수 카운터(th_Count)의 값 이상이 되면 Reset_Ctrl() 함수를 호출하여 쓰레드를 중단 시킵니다.

폼이 종료 될때 해야 할 일을 기술하기 위해 Closing 이벤트를 생성해야 합니다.

폼 디자인 에서 폼을 선택한 후, 속성창에 보면 번개모양(이벤트) 아이콘이 있습니다.
여기서 FormClosing 부분을 찾은다음, 옆부분에 커서가 위치한 부분의 공란을 더블클릭 하여 줍니다.

그리하면, Form1 의 Closing 이벤트로 넘어옵니다.
여기서 할일은 쓰레드를 중단 하는것 입니다.

폼(Form1)이 종료될 때 쓰레드의 시작 플래그를 false 상태로 만들고, 쓰레드를 중단시킵니다.

컴파일 후, 실행하면 이렇게 나옵니다.
여러 개의 쓰레드가 동시에 동작을 하면서 sPrint()함수 에서 미처 줄바꿈을 실행하기도 전에 다른 쓰레드로 부터 값이 마구 들어와서 생기는 문제입니다.

다음과 같이 수정해 봅시다.
textBox1에 문자 기록하고 줄바꿈 하는 작업에 lock()을 씌워 봅시다.

그리고 다시 실행을 하면...
이제야 뭔가 형태를 갖춰서 실행이 됩니다.

lock() 을 걸게 되면 lock()이 풀릴때 까지 그 내부 코드에 다른 코드가 간섭을 못하게 잠금처리 해주는거 같아보이는 군요...

그런데... 순서가 좀 이상하죠? 숫자의 순서가 뒤죽박죽 입니다.
그럼 다른 부분에 잠금 처리를 하여 보겠습니다.

일단 sPrint 부분의 lock() 을 다시 제거 하여 줍니다.

변수 i 의 값을 증가 시키고 출력 시키는 부분에 lock()를 걸어 봅시다.
여기서는 AA() 의 수정된 코드만 표시합니다만, 실제로 BB()와 CC()도 이렇게 수정하여야 합니다.

변수 i의 값을 증가 시키고, 문자형으로 변환, 출력 하는 부분을 lock 으로 감싸서 도중에 다른코드로 부터 간섭을 받지 않도록 수정하였습니다.

이제 실행하게되면...
숫자가 정상적으로 순서대로 출력되는 것을 볼 수 있습니다.

숫자 앞의 쓰레드 문자는 랜덤 입니다.
실행 할때 마다 다른 쓰레드가 뜬다는거죠...

근데 한가지... 300 번 반복 시켰는데 302 ??

여기 올리지는 않았지만 쓰레드 1개를 제거하고 다시 돌리니 301 까지 뜨는것으로 봐서 쓰레드 3개 가 동시에 돌다가 중단 처리 하는 과정에 나머지 2개가 미처 실행중이던 내용을 기록하는게 아닌가 추측해 봅니다.



*** 위에서 AA(), BB(), CC() 부분은 내용이 거의 비슷비슷 합니다.
이것을 좀더 간단하게 만들어 봤습니다.
th_work() 함수를 작성하여 그것을 호출하였습니다.

실컷 다 만들어 놓고 다 써놓고 나서 생각나서 걍 생각나는대로 끄적여 봤습니다. ^^
저렇게 바꿔도 결과는 동일 합니다.

Posted by 해비
2009.09.20 19:37



프로그래스 바를 활용한 쓰레드 예제 프로그램 입니다.
반복 횟수는 상단의 텍스트 상자를 활용해서 자유롭게~~~ 조절(?)이 가능합니다.

개발 환경
- Visual Studio 2005 (SP1)
- Windows Vista Home Premium K (32-bit)


내부 예제
- 스레드 생성 및 활용 (1개의 서브 쓰레드 생성)
- 쓰레드 중단 및 재개 (Pause 버튼과, Resume 버튼으로 제어)
- 실수 연산 및 결과를 소숫점 2째 자리 까지 잘라서 표현


메모
- 소스 내부에 주석이 달려있으며, 내용중 잘못된 부분 또는 버그가 존재 할수도 있습니다.

- 반복루프문 동작중에는 CPU점유율이 좀 높습니다.

- 이유는 잘 모르겠지만, 그 비주얼 스튜디오 디버깅 상태에서는 카운트 횟수가 올라가질 않더군요
  (Debug 폴더 안의 파일을 더블클릭 해서 실행 시키면 정상 동작 합니다.)

- 경고가 3개 있는데 아직 수정할 능력이 되지를 않네요 ㅎㄷㄷ
  suspend 1개, resume 2개 인데, 이거 쓰지 말고 다른 방법으로 하라는거 같은데 좀더 알아 봐야 되겠네요...

- [09/09/21] 패치에서 중단, 재개 기능은 쓰레드를 중단 시켰다가 새로이 초기화 해서 동작하는 방향으로 틀어버렸습니다.

- 변수는 전역변수 인지라 앞의 쓰레드가 하던 작업이 그대로 저장되어있다는 걸 이용한건데 이래도 되는건지...



수정
[09/09/21]
- 종료 관련 문제가 있어 Suspend와 Resume를 아예 빼버렸습니다 (-_-)

[09/09/20 - #2]
- 중단한 상태에서 종료시 프로세서가 계속 남아있는 문제를 수정하였습니다.



C# 접한지 얼마 안되는 초보 입니다. JAVA 책 보다가 갑자기 C# 할일이 생겨서 말이죠...
쓰레드 라는것을 처음 접하면서 책, 인터넷 뒤져가며 예제로 만들어 본 것인데...
고작 이거 하나 만들고 주말이 지나가 버렸네요 -ㅅ-;;

잘못된 부분 지적 환영합니다(^^)


주석부분, 제작자 부분 을 무단 수정하여 재배포 하는 일은 자제해 주시기 바랍니다.
Posted by 해비