C# 윈폼에서 창 열고 닫는 소스코드 입니다.
단순히 .Show()만 하면 되지 않느냐구요??
(직접 겪어보시믄 이게 왜 필요한지 알게 됩니다잉~)
여기서 ntcDF는 Form객체 입니다.
창 열기
private void showNotice() |
창 닫기
private void closeNotice() |
C# 윈폼에서 창 열고 닫는 소스코드 입니다.
단순히 .Show()만 하면 되지 않느냐구요??
(직접 겪어보시믄 이게 왜 필요한지 알게 됩니다잉~)
여기서 ntcDF는 Form객체 입니다.
창 열기
private void showNotice() |
창 닫기
private void closeNotice() |
컬럼(Column) 잠그기
this.fpSpread1_Sheet1.Columns.Get(0).Locked = true; |
컬럼(Column) 정렬기능 추가
1 | this.fpSpread1.ActiveSheet.SetColumnAllowAutoSort(-1, true); |
2 | this.fpSpread1.Sheets[0].Columns[1].AllowAutoSort = true; |
- Column 헤더 클릭 시 해당 Column 기준으로 데이터를 정렬하여 표시 해 준다.
- [1] 또는 [2] 중 한가지를 선택 적용한다.
현재 선택한 Row 색칠하기(잠겨진 셀 포함)
//잠긴 셀에 지정된 색상 해제 |
- 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 = "코드"; |
- 컬럼 헤더 타이틀, 컬럼의 가로길이 설정 예.
멀티라인 텍스트 데이터 가져오기
private DataTable _rtnDT; // 전역변수 선언 // 스프레드에 데이터 바인딩 _rtnDT = _controller.getData(); fpSpread1.DataSource = _rtnDT; // 스프레드 내용 참조 시 iRow = fpSpread1.ActiveSheet.ActiveRowIndex; txtProhAbbr.Text = _rtnDT.Rows[iRow][0].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 셀 모두 합쳐 진다.
엑셀 내보내기
// 스프레드에 내보낼 정보 적재 |
- SaveFileDialog 컨트롤 을 호출하여 저장할 위치, 파일명을 입력받고, 스프레드의 내용을 해당 위치에 내보낸다.
- 스프레드 속성 중 Visible = false 인 경우, 시트 없는 빈 엑셀 파일이 생성되므로 주의한다.
다룰 내용...
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가 되므로 시작일 하루를 가산하여 보정해 줘야 한다.
시작일 가산...? 다른 표현 방법이 떠오르진 않지만 여튼 뭐 그렇다.
더 좋은 방법 및 의견 코멘트 환영합니다. ^__^
조금 특이한 케이스를 잡아서 소개합니다.
데이터셋과 콤보박스가 연결된 상태에서 발생하는 문제입니다.
해당 문제를 재현한 프로그램
환경 : C#.NET 1.0 WinForm
상황 : ComboBox 컨트롤의 값을 코딩으로 변경하였는데 변경된 값이 실제로 반영되지 않는 문제.
(실행파일 & 소스 포함, 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 만 설치된 컴퓨터에서 프로그램 실행시 증상이 나타나지 않는 것을 확인하였습니다.
소스코드는 압축파일내에 들어있으며, 주석까지 달려 있어서 이해하는데 그리 어렵지는 않을 것입니다.
[구동설명]
1. 랜덤함수로 임의의 숫자를 생성한다음
2. 그 숫자에 대응하는 각각의 문자를 출력하도록 하였습니다.
3. 문자는 아스키 코드값을 그에 해당하는 문자출력하는 방식으로 만들어졌습니다.
[주석이 포함된 소스코드 및 실행파일]
나름 간단하게? 구현해본 백트래킹 (맞는지는 잘 모르겠으나 어쨋든 백트래킹으로 명명)입니다.
입력받은 배열의 값에 대해서 가능한 모든 순서조합을 만들어냅니다.
단, 모든 순서조합을 위해서는 최초에 배열의 수가 오름차순으로 정렬되어져 있어야 합니다.
최종적인 형태는 내림차순정렬이 되어져 있으며, 이때 함수는 더이상 처리를 하지 않고 들어온 값 그대로 리턴 시켜 버립니다.
내림차순 정렬이 완료 되었으나, 맞는 조합이 없었다면, 해당 문제는 해가 없는 것이 됩니다. (즉, 풀수 없는 문제...)
매번 시도 마다 다음 조합으로 만들어 냅니다. (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} 로 바뀌는 과정을 설명합니다.
// 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;
}
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; // 반복이 끝나면 곱한 수의 결과값을 리턴
}
// ----------------------------------------------------------------------
ThreadEx1의 개량형 버젼입니다.
기존에는 반복횟수를 카운트 하는 쓰레드 에서 표시까지 직접하였었는데, 컨트롤에 텍스트 표시하는데 걸리는 CPU의 부하 라던가 시간을 생각하다가 그냥 반복만 돌면 스피드가 얼마나 나올까 하는 생각에 제외시키기로 해보았습니다.
하지만 반복이 끝나기까지 마냥 기다리려면 좀 답답한 감이 있으니... 별도로 쓰레드를 생성하여 반복루프를 도는 작업쓰레드의 진행상황을 표시해 주는것으로 짜 보았습니다.
실제로 루프 카운트 는 AA() 에서 올라가고, BB()는 AA()의 현재 진행상황을 비동기로 알려주고 있습니다.
예상했던 대로 엄청난 스피드를 보여주더군요^^
120000000 번의 반복을 10초도 안걸려서 끝내버렸습니다.
(Core 2 Duo T7300, 4GB DDR2, Win7, .NET2.0)
쓰레드2의 반복(표시)횟수는 쓰레드1과 동기화를 하지 않고 있으며, 쓰레드1이 끝날 때 같이 끝나게 되어있으므로 매번 카운트 횟수는 다르게 나옵니다.
기존에는 모든 반복카운트에 표시를 해주었다면...
이번에는 중간중간 빼먹어 가면서 표시를 해 주고 있다고 보면 됩니다.