반응형

안녕하세요

 

코딩연습생입니다

 

이번 시간에 포스팅하고자 하는건 제목에도 나와 있지만

 

MSSQL을 통해서 C#으로 DataGridView 컨트롤의 컬럼을 동적으로 생성하게 하여

 

한 페이지에서 여러 Data를 조회 할 수 있는 유동적인 DataGirdView를 사용하는 방법을 포스팅 해볼려고 합니다

 

말은 거창한데 결국은 데이터그리드뷰의 속성을 하나씩 설정해서 유동적으로 사용하게 하는 방법입니다

 

첫번째는 조회 타입에 따라 변화 할 그리드뷰의 속성을 MSSQL에서 프로시져로 지정 합니다

 

IF @GUBUN = 'COL_CNT_MANDO'
		BEGIN
			SELECT 37 AS CNT    --전체 컬럼 출력수
		END
		
		IF @GUBUN = 'COL_CNT_ETC'
		BEGIN
			SELECT 22 AS CNT    --전체 컬럼 출력수
		END


		IF @GUBUN = 'COL_NAD_MANDO'
		BEGIN
			SELECT '고객코드' AS COL_NM
			UNION ALL
			SELECT '고객명' AS COL_NM
			UNION ALL
			SELECT 'ERP 품번' AS COL_NM
			UNION ALL
			SELECT '거래선 도번' AS COL_NM
			UNION ALL
			SELECT '납품처코드' AS COL_NM
			UNION ALL
			SELECT '납품처명' AS COL_NM
			UNION ALL
			SELECT '차종명' AS COL_NM
			UNION ALL
			SELECT '*D+0(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+0(야간)' AS COL_NM
			UNION ALL
			SELECT '*D+1(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+1(야간)' AS COL_NM
			UNION ALL
			SELECT '*D+2(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+2(야간)' AS COL_NM
			UNION ALL
			SELECT '*D+3(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+3(야간)' AS COL_NM
			UNION ALL
			SELECT '*D+4(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+4(야간)' AS COL_NM
			UNION ALL
			SELECT '*D+5(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+5(야간)' AS COL_NM
			UNION ALL
			SELECT '*D+6(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+6(야간)' AS COL_NM
			UNION ALL
			SELECT '*D+7(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+7(야간)' AS COL_NM
			UNION ALL
			SELECT '*D+8(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+8(야간)' AS COL_NM
			UNION ALL
			SELECT '*D+9(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+9(야간)' AS COL_NM
			UNION ALL
			SELECT '*D+10(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+10(야간)' AS COL_NM
			UNION ALL
			SELECT '*D+11(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+11(야간)' AS COL_NM
			UNION ALL
			SELECT '*D+12(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+12(야간)' AS COL_NM
			UNION ALL
			SELECT '*D+13(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+13(야간)' AS COL_NM
		END

		IF @GUBUN = 'COL_NAD_ETC'
		BEGIN
			SELECT '고객코드' AS COL_NM
			UNION ALL
			SELECT '고객명' AS COL_NM
			UNION ALL
			SELECT 'ERP 품번' AS COL_NM
			UNION ALL
			SELECT '거래선 도번' AS COL_NM
			UNION ALL
			SELECT '납품처코드' AS COL_NM
			UNION ALL
			SELECT '납품처명' AS COL_NM
			UNION ALL
			SELECT '차종명' AS COL_NM
			UNION ALL
			SELECT '*D+0' AS COL_NM
			UNION ALL
			SELECT '*D+1' AS COL_NM
			UNION ALL
			SELECT '*D+2' AS COL_NM
			UNION ALL
			SELECT '*D+3' AS COL_NM
			UNION ALL
			SELECT '*D+4' AS COL_NM
			UNION ALL
			SELECT '*D+5' AS COL_NM
			UNION ALL
			SELECT '*D+6' AS COL_NM
			UNION ALL
			SELECT '*D+7' AS COL_NM
			UNION ALL
			SELECT '*D+8' AS COL_NM
			UNION ALL
			SELECT '*D+9' AS COL_NM
			UNION ALL
			SELECT '*D+10' AS COL_NM
			UNION ALL
			SELECT '*D+11' AS COL_NM
			UNION ALL
			SELECT '*D+12' AS COL_NM
			UNION ALL
			SELECT '*D+13' AS COL_NM
		END

위의 쿼리내용을 보게 되면 미리 타입에 따라 컬럼 갯수와 컬럼명칭을 설정해서 가져오기 위한 쿼리 입니다

 

유동적인 그리드뷰를 적용시킬 윈폼 페이지 안에 아래와 같이 코딩을 합니다

 

private void Grid_Column()
        {
            this.Cursor = Cursors.WaitCursor;   //마우스 커서를 Waitting

            dataGridView1.Rows.Clear();  //그리드뷰 초기화
            dataGridView1.Columns.Clear(); //

            string query = "";
            if (radioButton1.Checked == true)
            {
                query += "EXEC SP_SHIP_CUST_PLAN ";
                query += "     'COL_CNT_MANDO'";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";

            }
            else
            {
                query += "EXEC SP_SHIP_CUST_PLAN ";
                query += "     'COL_CNT_ETC'";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
            }
            
            
            //MSSQL 프로바이더
            DB db = new DB();
            DataTable dt = db.ExcuteQuery(query);

            //datatable의 내용을 그리드에 display
            foreach (DataRow row in dt.Rows)
            {
                dataGridView1.ColumnCount = Convert.ToInt32(row[0].ToString());
            }

            dt.Clear();


            query = "";
            if (radioButton1.Checked == true)
            {
                query += "EXEC SP_SHIP_CUST_PLAN ";
                query += "     'COL_NAD_MANDO'";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
            }
            else
            {
                query += "EXEC SP_SHIP_CUST_PLAN ";
                query += "     'COL_NAD_ETC'";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
            }
            dt = db.ExcuteQuery(query);

            int i = 0;

            //datatable의 내용을 그리드에 display
            foreach (DataRow row in dt.Rows)
            {
                dataGridView1.Columns[i].Name = row["COL_NM"].ToString();
                //sGridView1.Columns[i].SortMode = DataGridViewColumnSortMode.NotSortable;

                //숫자컬럼은 앞에*를 붙였기때문에 숫자컬럼은 모두 오른쪽 정렬을 취함
                if (row["COL_NM"].ToString().Substring(0, 1) == "*")
                {
                    dataGridView1.Columns[i].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;  //우측정렬
                }
                //문자열은 좌측정렬구분자를 공백으로 처리
                else if (row["COL_NM"].ToString().Substring(0, 1) == " ")
                {
                    dataGridView1.Columns[i].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft;  //좌측정렬
                }
                else
                {
                    dataGridView1.Columns[i].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;  //가운데정렬
                }

                i++;
            }

            this.Cursor = Cursors.Default;
            dataGridView1.AllowUserToAddRows = false;
        }

 

여기서 MSSQL DB에 접속하기 위한 프로바이더는 별도 함수로 작성해서 사용하였습니다

 

함수 제작하는 방법은 아래 링크 페이지에서 확인 하시기 바랍니다

 

https://codingman.tistory.com/73

 

[C#] MSSQL 접속하고 사용하기

안녕하세요 C# 컨텐츠로 블로그를 운영중인 코딩 연습생입니다 이번 포스팅에서는 C#으로 MSSQL를 접속하고 쿼리문을 전송시켜 연동시키기까지 한번 해보도록 하겠습니다 일반적인 방법으로는 1) 접속정보 생성 2)..

codingman.tistory.com

 

이렇게 타입에 따른 그리드뷰 상세 옵션을 MSSQL에서 불러와서 그리드를 그려준뒤에 각 컬럼에 맞게 뿌려주면 됩니다

 

저는 유동적으로 생성된 그리드뷰에 엑셀파일을 불러오기로 구현하였습니다

 

private void hoverGradientButton3_Click(object sender, EventArgs e)
        {
            OpenFileDialog oFileDialog = new OpenFileDialog();
            oFileDialog.Filter = "Excel (*.xlsx)|*.xlsx|Excel 97-2003 (*.xls)|*.xls";

            if (oFileDialog.ShowDialog() != DialogResult.OK)
            {
                return;
            }

            Excel.Application xlApp;
            Excel.Workbook xlWorkBook;
            Excel.Worksheet xlWorkSheet;
            Excel.Range range;

            string str;
            int rCnt = 0;
            int cCnt = 0;
            string sCellData = "";
            double dCellData;

            xlApp = new Excel.Application();
            xlApp.DisplayAlerts = false;
            xlApp.Visible = false;
            xlApp.ScreenUpdating = false;
            xlApp.DisplayStatusBar = false;
            xlApp.EnableEvents = false;

            SplashWnd.SplashShow();

            try
            {
                xlWorkBook = xlApp.Workbooks.Open(oFileDialog.FileName, 0, true, 5, "", "", true, Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
                xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);

                range = xlWorkSheet.UsedRange;

                DataTable dt = new DataTable();

                // 첫 행을 제목으로
                for (cCnt = 1; cCnt <= range.Columns.Count; cCnt++)
                {
                    str = (string)(range.Cells[1, cCnt] as Excel.Range).Value2;
                    dt.Columns.Add(str, typeof(string));
                }

                for (rCnt = 3; rCnt <= range.Rows.Count; rCnt++)
                {
                    string sData = "";
                    for (cCnt = 1; cCnt <= range.Columns.Count; cCnt++)
                    {
                        try
                        {
                            sCellData = (string)(range.Cells[rCnt, cCnt] as Excel.Range).Value2;
                            sData += sCellData + "|";
                        }
                        catch (Exception ex)
                        {
                            dCellData = (double)(range.Cells[rCnt, cCnt] as Excel.Range).Value2;
                            sData += dCellData.ToString() + "|";
                        }
                    }
                    sData = sData.Remove(sData.Length - 1, 1);
                    dt.Rows.Add(sData.Split('|'));
                }

                int i = 0;

                if (radioButton1.Checked == true)
                {
                    foreach (DataRow row in dt.Rows)
                    {
                        dataGridView1.Rows.Add(1);

                        for (int j=0; j<= 34; j++)
                        {    
                            dataGridView1.Rows[i].Cells[j].Value = dt.DefaultView[i][j].ToString();
                        }
                       
                        i++;
                    }
                }
                else
                {
                    foreach (DataRow row in dt.Rows)
                    {
                        dataGridView1.Rows.Add(1);

                        for (int j = 0; j <= 20; j++)
                        {
                            dataGridView1.Rows[i].Cells[j].Value = dt.DefaultView[i][j].ToString();
                        }


                        i++;
                    }
                }
                
                //dataGridView1.DataSource = dt.DefaultView;

                xlWorkBook.Close(true, null, null);
                xlApp.Quit();

                releaseObject(xlWorkSheet);
                releaseObject(xlWorkBook);
                releaseObject(xlApp);

                SplashWnd.SplashClose(this);

            }
            catch (Exception ex)
            {
                MessageBox.Show("파일 열기 실패! : " + ex.Message);
                return;
            }
        }

        private void releaseObject(object obj)
        {
            try
            {
                System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
                obj = null;
            }
            catch (Exception ex)
            {
                obj = null;
                MessageBox.Show("Unable to release the Object " + ex.ToString());
            }
            finally
            {
                GC.Collect();
            }
        }

 

이렇게 되면 불러오고자 하는 엑셀 문서의 타입에 따라 데이터그리드뷰를 생성시켜 주고 그 위에 엑셀의 내용을 

 

불러오기 하여 보여질수 있게 됩니다

 

엑셀 양식 불러오기를 사용할때 고객의 종류? 양식의 타입?에 따라 변동이 많을시에 이렇게 데이터그리드뷰를 

 

유동적으로 변화시킬수 있다면 굳이 여러개의 폼을 만들지 않고 하나의 폼에서 처리가 가능하니 조금 사용자 입장에서

 

편리할수 있다고 생각해서 구현해 봤습니다

 

 

반응형
반응형

안녕하세요

 

코딩 연습생입니다

 

아직도 코로나19로 인해서 기업들 소상인 분들 모두 참 어렵게 지내고 계시는거 같습니다

 

저 또한 회사원으로 회사가 많이 힘들어 지고 있다고 체감할 정도니깐요

 

그래도 국가에서 이래저래 도움을 줄 방법을 많이 고민하고 시행할려고 하는거 같은데 어찌 될지는 잘 모르겠네요

 

그래도 저희는 의지에 한국인 아니겠습니까?

 

이 또한 잘 이겨내리라 생각하고 열심히 살아봐야겠죠!?ㅋㅋ

 

블로그를 운영하면서 참 은근히 스트레스를 받네요 빨리 빨리 더 많은 정보를 공유하고 싶은데

 

글하나 쓰기까지 참 시간이 많이 소요 됩니다~ 거기에 회사 일을 하면서 해야 하는지라 쉽지가 않네요

 

평소 인터넷 검색을 통해 많은 블로거 분들의 글을 아무 생각없이 읽어 넘겼었는데 요즘은 참 많은 생각이 듭니다

 

역시 사람을 겪어봐야 느끼는 동물이라는게 새삼 느껴지네요ㅎ

 

예전 포스팅중에 엑셀 파일을 읽어서 그리드뷰에 불러오기하는 포스팅을 올린적이 있는데

 

그거와 유사한 기능을 구현해 볼겁니다

 

https://codingman.tistory.com/11

 

[C#] 엑셀파일 내보내기(그리드뷰)

///

/// 데이타 테이블을 엑셀로 받아온다. //////원본 데이타 테이블. ///원본 데이타 테이블의 컬럼들. ///codingman.tistory.com

 

블로그 초기 운영때 올린 글이라 별다른 설명이 없이 기능 소스만 공개 했었네요ㅎ

 

위의 포스팅과 차이점은 이미 템플릿화된 파일을 프로젝트에 삽입한뒤에 DB의 값을 불러오기하여 엑셀이 뿌려주는

 

겁니다

 

그렇게 되면 엑셀파일에는 항상 최산의 데이터가 자동 삽이된 상태로 사용자가 문서를 열어볼수 있는거죠

 

구현이 어렵지는 않지만 생각의 발상 차이라고 할수 있을거 같습니다

 

첫번째로 프로젝트에 템플릿으로 사용할 엑셀 문서를 포함 시켜 줍니다

 

 

프로젝트명칭은 회사에서 사용되는 시스템을 수정한것이라 혹시 몰라 숨김 처리 하였습니다ㅎㅎ

 

저기에 삽입된 엑셀 문서에는 셀마다 자동 수식이 걸려있는 문서 말그대로 템플릿 파일입니다

 

빈 셀에 DB의 값을 넣어주면 자동으로 수식에 의해 계산이 되겠죠?

 

음...엑셀(템플릿)파일의 내용을 열어서 보여드리고 싶지만 회사정보가 나오기 때문에 생략하겠습니다

 

메인 화면에서 아래와 같이 Excel 내려받기를 실행할 버튼을 생성해 줍니다

 

 

대충 감이 오실겁니다 고객 생상 일정 정보를 토대로 회사내 출하 계획을 생성하는 프로그램을 만들고 있는 화면중에

 

하나입니다ㅎㅎㅎ

 

자 그러면 해당 버튼을 클릭했을때 시행될 이벤트 코드를 생성해야겠지요?

 

Excel 내려받기 버튼의 클릭이벤트를 생성합니다

 

 

생성된 이벤트에 다음과 같이 코딩을 해줍니다

 

private void hoverGradientButton1_Click(object sender, EventArgs e)
        {
            string ExcelPath = Environment.CurrentDirectory + @"\Excel\Shipping_semple.xlsx";
            string ExcelEndPath = Environment.CurrentDirectory + @"\Excel\Shipping_semple_" + DateTime.Now.ToString("yyyyMMdd") + ".xlsx";

            //파일생성유무 확인(기준 하루 한번 생성이 가능 재생성시 그존 파일 삭제.
            if (File.Exists(ExcelEndPath))
            {
                File.Delete(ExcelEndPath);
            }


            try
            {
                ExcelApp = new Excel.Application();
                wb = ExcelApp.Workbooks.Open(ExcelPath,
                                             0,
                                             true,
                                             5,
                                             "",
                                             "",
                                             true,
                                             Excel.XlPlatform.xlWindows,
                                             "\t",
                                             false,
                                             false,
                                             0,
                                             true,
                                             1,
                                             0);
                ws = wb.Worksheets["Sheet1"] as Excel.Worksheet;

                //엑셀 시트 인덱스 번호는 0,0 부터 시작 하는 것이 아니라 1,1 A1 부터 시작 함. 0,0 으로 시작하면 오류... 
                //시트에 값 쓰기... 
                string query = "SELECT 고객,";
                query += "             납품처,";
                query += "             품목정보,";
                query += "             목표품번,";
                query += "             제품단위,";
                query += "             제품스팩";
                query += "        FROM 품목마스터";
                
                //DB 연결 클래스 입니다
                DB db = new DB();
                
                DataTable dt = db.ExcuteQuery(query);

                if (dt.Rows.Count > 0)
                {
                    for (int i = 0; i <= dt.Rows.Count - 1; i++)
                    {
                        ws.Cells[7 + i, 1] = dt.Rows[i]["고객"].ToString();
                        ws.Cells[7 + i, 2] = dt.Rows[i]["납품처"].ToString();
                        ws.Cells[7 + i, 3] = dt.Rows[i]["품목정보"].ToString();
                        ws.Cells[7 + i, 4] = dt.Rows[i]["목표품번"].ToString();
                        ws.Cells[7 + i, 5] = dt.Rows[i]["제품단위"].ToString();
                        ws.Cells[7 + i, 6] = dt.Rows[i]["제품스팩"].ToString();
                    }

                }

                //다른 이름으로 저장하기... 
                //wb.Save(); 
                // => 오픈한 파일 그대로 저장... 
                if (File.Exists(ExcelEndPath)) File.Delete(ExcelEndPath);
                wb.SaveAs(ExcelEndPath);

                //파일 닫기... 
                wb.Close(false, Type.Missing, Type.Missing);
                wb = null;
                ExcelApp.Quit();

                MessageBox.Show("엑셀 파일 생성이 완료 되었습니다.");

            }
            catch (Exception ex)
            {
                //객체들 메모리 해제 
                ReleaseExcelObject(ws);
                ReleaseExcelObject(wb);
                ReleaseExcelObject(ExcelApp);
                GC.Collect();
            }
            finally
            {
                //객체들 메모리 해제 
                ReleaseExcelObject(ws);
                ReleaseExcelObject(wb);
                ReleaseExcelObject(ExcelApp);
                GC.Collect();
            }
        }

 

버튼을 클릭해서 템플릿 파일을 생성하게 되면 원본파일이 아닌 생성일자가 붙어 있는 신규 파일이 생성됩니다

 

 

내가 원하는 Cell위치에 DB 값이 들어가 있는 템플릿 파일이 생성된거죠

 

제가 개발로 사용하고 있는 노트북이 구형이라 속도가 많이 느릴경우 메모리를 늘려보시는것도 방법이 될거 같습니다

 

 

반응형
반응형

안녕하세요

 

코딩연습생입니다 정말 오랜만에 C# .Net으로 돌아왔습니다

 

회사에서 진행할려는 프로그램중 작업자가 터치로 사용해야할 프로그램인데

 

닷넷에서 제공해주는 일반 체크박스는 크기가 너무 작고 크기 조절도 불가능하여

 

나만의 체크박스 컨트롤을 만들어서 적용해야겠다라는 생각에 만들게 되었는데

 

저와 같이 필요하신분들을 위해 제작과정과 사용 방법에 대해서 포스팅 하도록 하겠습니다

 

물론 저도 처음부터 끝까지 제가 만든것은 아닙니다 검색하고 구현해보고 수정해서 나에게 필요한 형태로

 

변환해서 사용하는거죠

 

그러면 시작해보도록 하겠습니다

 

비쥬얼 스튜디오 2017(제가 사용한 버전입니다)를 실행해서 윈폼 형식의 프로젝트를 생성합니다

 

1. 프로젝트 생성하기

 

2. Windows Forms 형식의 폼을 생성합니다

 

3. 프로젝트가 생성된 위치에 컨트롤로 사용할 윈폼 형식의 폼을 하나 추가해 줍니다

 

4. 추가할려는 폼의 명칭은 CustomCheckBox로 지정했습니다

 

 

5. 추가로 생성한 CustomCheckBox에 다음과 같이 코딩합니다

 

*CustomCheckBox.cs

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;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace WindowsFormsApp1
{
    public partial class CustomCheckBox : System.Windows.Forms.Control
    {
        private bool _check = false;

        public bool Check
        {
            get
            {
                return _check;
            }
            set
            {
                _check = value;
                Invalidate();
            }
        }

        public CustomCheckBox()
        {
            InitializeComponent();
        }
        public CustomCheckBox(IContainer container)
        {
            container.Add(this);
            InitializeComponent();
        }
        protected override void OnPaint(PaintEventArgs pe)
        {
            Graphics g = pe.Graphics;

            g.FillRectangle(new SolidBrush(Color.Transparent), this.ClientRectangle);

            ControlPaint.DrawCheckBox(g, 1, 1, this.ClientRectangle.Height - 2, this.ClientRectangle.Height - 2, _check ? ButtonState.Checked : ButtonState.Normal);

            g.DrawString(this.Text, this.Font, new SolidBrush(Color.Black), this.ClientRectangle.Height + 2, (this.Height - g.MeasureString(this.Text, this.Font).Height) / 2);
        }
        private void CustomCheckBox_Click(object sender, System.EventArgs e)
        {
            _check = !_check;
            Invalidate();
        }

    }
}

 

*CustomCheckBox.Designer.cs

namespace WindowsFormsApp1
{
    partial class CustomCheckBox
    {
        /// <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 구성 요소 디자이너에서 생성한 코드

        /// <summary>
        /// 디자이너 지원에 필요한 메서드입니다.
        /// 이 메서드의 내용을 코드 편집기로 수정하지 마십시오.
        /// </summary>
        private void InitializeComponent()
        {
            components = new System.ComponentModel.Container();
            this.Click += new System.EventHandler(this.CustomCheckBox_Click);
        }

        #endregion
    }
}

 

6. 빌드 후 Form1의 폼 디자인으로 이동한 다음 도구상자를 열어보시면 다음과 같은 컨트롤이 생성됩니다

 

7. CustomCheckBox 컨트롤을 드래그앤드롭하여 Form1에 가져갑니다

 

그렇게 하면 상하좌우 크기 조절이 가능한 커스텀 체크박스 컨트롤을 사용할 수 있습니다

 

반응형
반응형

안녕하세요

 

제 블로그에 있는 OpenCv 예제 포스팅을 따라하시던분께서 요청하신 DLL 파일입니다

 

제가 연습한 부분에서는 굳이 사용하지 않으셔도 되는 파일이지만 필요하실수도 있을거 같아서

 

업로드해 드립니다

 

해당 DLL파일은 Nuget 설치시 패키지에 포함된 DLL파일이 아닌 Sharp 사용자가 개인 컨버팅을 통해

 

제작한 파일로 알고 있습니다

 

OpenCv를 통해 SVM 구현시에 사용되는걸로 알고 있는데

 

필요하신 분은 아래 링크를 통해 다운로드 받으시길 바랍니다

 

OpenCvSharp.MachineLearning.zip
0.02MB

반응형
반응형

안녕하세요

 

이번 시간 포스팅 내용은 제목과 똑같이 원본이미지에서 찾고자 하는 부분이미지를 매칭하여

 

원본이미지에 해당 부분을 검출해 내는 기능입니다

 

이미 인터넷상에 많은 정보가 있기에 별도 설명은 생략하고 바로 기능 구현으로 넘어가겠습니다

 

해당 포스팅도 저번 포스팅에 이어 진행됨에 따라 내용이 중간 생략 부분이 있을 수 있으니

 

이해가 잘되시면 이전 포스팅을 검색해 보시기 바랍니다

 

https://codingman.tistory.com/49

 

[C#]OpenCvSharp 라이브러리 사용하기 #1

안녕하세요 저번 포스팅에 C#으로 OpenCvSharp 라이브러리를 등록하여 구현하는 포스팅을 준비하던중에 OpenCv 3,4 버전에서 오류가 발생하는 문제가 있다는 얘길 듣고 부랴부랴 포스팅 내용을 검토해봤는데 역시..

codingman.tistory.com

 

템플릿 매칭을 하기 위해 두개의 이미지를 불러와야 하는데요

 

그러기 위한 디자인 UI 부터 보여드릴께요

 

[디자인]

- 메뉴에서 유틸리티 -> 템플릿매칭 버튼을 생성

 

- 해당 버튼에서 발생할 클릭 이벤트 활성화

 

- 이벤트 구문에 다음과 같이 소스 코딩 합니다

        private void 템플릿매칭ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (src == null) return;
            using (Match Sq = new Match())
            using (IplImage temp = Sq.Templit(src, src2))
            {
                result = temp.Clone();

            }

            using (CvWindow wind = new CvWindow("결과창"))
            {
                wind.Image = result;
                Cv.WaitKey(0);
            }
        }

 

- 템플릿 매칭 기능이 동작할 클래스를 하나 생성합니다

 

- 생성된 클래스에 다음과 같으 코딩합니다

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenCvSharp;

namespace OpenCV_V1
{
    class Match : IDisposable
    {
        IplImage match;

        public IplImage Templit(IplImage src, IplImage temp)
        {
            match = src;
            IplImage templit = temp;
            IplImage tm = new IplImage(new CvSize(match.Size.Width - templit.Size.Width + 1, match.Size.Height - templit.Size.Height + 1), BitDepth.F32, 1);

            CvPoint minloc, maxloc;
            Double minval, maxval;

            Cv.MatchTemplate(match, templit, tm, MatchTemplateMethod.SqDiffNormed);

            Cv.MinMaxLoc(tm, out minval, out maxval, out minloc, out maxloc);

            Cv.DrawRect(match, new CvRect(minloc.X, minloc.Y, templit.Width, templit.Height), CvColor.Red, 3);

            return match;
        }

        public void Dispose()
        {
            if (match != null) Cv.ReleaseImage(match);
        }
    }
}

 

- 그림읽기를 통해 원본 이미지를 불러옵니다

 

- 그림읽기2를 통해 매칭 이미지를 불러옵니다

 

- 유틸리티 -> 템플릿매칭 버튼을 눌러 결과를 확인 합니다

 

[결과 창]

 

- 이렇게 매칭 이미지(쯔위)를 원본이미지에서 검출해 내는것을 확인 할 수 있습니다

 

- 프로그램을 구현하신뒤 다른 이미지로 테스트 해보시기 바랍니다

반응형
반응형

안녕하세요

 

이번 시간 포스팅할 부분은 OpenCvSharp를 이용한 PCA(Principal Component Analysis)를 구현해 볼려고 합니다

 

근데 아무 저와 똑같이 PCA가 뭐지??라는 분들이 많으실거 같아서 검색을 통해 제가 알아본 내용을

 

간략하게 소개 하고 구현 해보도록 할께요

 

▶ 주성분분석(Principal Component Analysis)

      - PCA는 분포된 데이터들의 주성분(Principal Component)를 찾아 고차원의 데이터를 저차원의 데이터로 환원

        시키는 기법

 

 

음... 정의를 보아도 무슨말인지 잘 이해가 되지 않습니다. 제가 이해한것을 표현하자면 어떤한 데이터의 주성분을

 

분석하여 데이터로 환원한뒤 그 환원된 값의 분포도에 따라 어떠한 형태를 띄고 있는지를 보는 거라고 이해하고

 

있는데 이게 맞는것인지를 모르겠습니다

 

제가 이해한 정의를 가지고 프로그래밍을 분석하여 구현하였는데

 

프로그램적 순서를 보면 이렇습니다 

 

① 원본 이미지

② 대상 이미지

③ 형상 비교를 통한 매치율 분석

 

이론은 간단하지만 구현하고 분석을 쉽지가 않더라구요 아무 저도 프로그래머다 보니 논리적 이론 보다는

 

프로그램적 구현쪽을 더 많이 파고 있는 입장이라 완벽한 설명은 불가합니다

 

좀 더 구체적 이해와 설명이 필요하시면 검색을 통해 이해 하시는게 좋을거 같습니다

 

그럼 다시 본론으로 돌아와서 프로그램 구현을 시작해 보겠습니다

 

해당 포스팅의 글 역시 기존 OpenCvSharp 포스팅 자료와 이어서 진행되오니

 

이해가 안가거나 중간 생략된 부분은 이전 포스팅을 참조하시기 바랍니다

 

https://codingman.tistory.com/49

 

[C#]OpenCvSharp 라이브러리 사용하기 #1

안녕하세요 저번 포스팅에 C#으로 OpenCvSharp 라이브러리를 등록하여 구현하는 포스팅을 준비하던중에 OpenCv 3,4 버전에서 오류가 발생하는 문제가 있다는 얘길 듣고 부랴부랴 포스팅 내용을 검토해봤는데 역시..

codingman.tistory.com

 

그럼 프로그램 동작을 위한 디자인 부분부터 설명하겠습니다

 

[디자인]

- 메뉴에 머쉰런닝 탭에 PCA 버튼을 만들고 학습과 검출의 세부 버튼을 생성합니다

 

- 학습과 검출 세부 버튼에 클릭시 동작 할 수 있도록 이벤트를 활성화 시킵니다

 

- 해당 이벤트에 다음과 같이 코딩합니다

 

* 학습

        private void 학습ToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            using (PCA pca = new PCA())
            using (IplImage temp = pca.LearnPCA())
            {
                if (temp == null)
                {
                    MessageBox.Show("데이타 파일 오류");
                    return;
                }
                result = temp.Clone();

            }
            pictureBoxIpl2.ImageIpl = result;
        }

 

*검출

        private void 검출ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (PCA pca = new PCA())
            {
                String[] temp = pca.recognize();
                if (temp == null) MessageBox.Show("오류발생 확인요망");
                for (int i = 0; i < temp.Length; i++)
                    listBox1.Items.Add(temp[i]);

            }
        }

 

- PCA 기능 동작을 위한 클래스 파일 생성합니다

 

- 생성된 클래스에 다음과 같이 소스코드를 작성 합니다

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using OpenCvSharp;

namespace OpenCV_V1
{
    class PCA : IDisposable
    {
        #region 초기값
        int nTrainFaces = 0;
        int nEigens = 0;

        IplImage result;
        IplImage[] faceImgArr;
        IplImage[] eigenVectArr;
        IplImage pAvgTrainImg;
        float[,] projectedTrainFaceMat;
        float[] eigenValMat;
        CvMat personNumTruthMat;

        public void Dispose()
        {
            if (result != null) Cv.ReleaseImage(result);
            if (!pAvgTrainImg.IsDisposed) pAvgTrainImg.Dispose();
            if (!faceImgArr[0].IsDisposed)
            {
                for (int i = 0; i < nTrainFaces; i++)
                {
                    faceImgArr[i].Dispose();
                }
            }
            if (!eigenVectArr[0].IsDisposed)
            {
                for (int i = 0; i < nEigens; i++)
                    eigenVectArr[i].Dispose();
            }
            if (!personNumTruthMat.IsDisposed) Cv.ReleaseMat(personNumTruthMat);
        }
        #endregion

        #region PCA 학습

        public unsafe IplImage LearnPCA()
        {
            //학습할 이미지 사진 파일명을 나열한 텍스파일 읽기
            nTrainFaces = loadFaceImgArray("train.txt");
            if (nTrainFaces < 2)
            {
                //MessageBox.Show("데이타 파일이 잘못 되었슴");
                return null;
            }

            doPCA();

            projectedTrainFaceMat = new float[nTrainFaces, nEigens];
            float[] tempProject = new float[nEigens];

            for (int i = 0; i < nTrainFaces; i++)
            {
                Cv.EigenDecomposite(faceImgArr[i], eigenVectArr, pAvgTrainImg, tempProject);//projectedTrainFaceMat[i]);
                projectedTrainFaceMat[i, 0] = tempProject[0];
                projectedTrainFaceMat[i, 1] = tempProject[1];
            }


            storeTraingData();
            return result;
        }

        private int loadFaceImgArray(String file)
        {
            //텍스트 파일에 나열되어진 파일명대로 이미지 읽어서 메모리에 저장하기   
            int i = 0;
            string[] lines = File.ReadAllLines(file); //학습할 파일명 획득
            faceImgArr = new IplImage[lines.Length]; //학습할 얼굴 갯수만큼 메모리 확보

            foreach (string line in lines) //텍스트 파일에서 읽은 파일명으로
            {
                faceImgArr[i] = new IplImage(lines[i], LoadMode.GrayScale); //사진이미지 읽어 오기
                i++;
            }
            return lines.Length;

        }

        private unsafe void doPCA()
        {
            CvTermCriteria calcLimit;
            CvSize faceImgSize;
            nEigens = nTrainFaces - 1;

            faceImgSize.Width = faceImgArr[0].Width;
            faceImgSize.Height = faceImgArr[0].Height;

            eigenVectArr = new IplImage[nEigens];

            for (int i = 0; i < nEigens; i++)
                eigenVectArr[i] = new IplImage(faceImgSize, BitDepth.F32, 1);

            eigenValMat = new float[nEigens];
            pAvgTrainImg = new IplImage(faceImgSize, BitDepth.F32, 1);
            calcLimit = new CvTermCriteria(CriteriaType.Iteration, nEigens, 1);
            Cv.CalcEigenObjects(faceImgArr, eigenVectArr, 0, calcLimit, pAvgTrainImg, eigenValMat);

        }

        //학습된 데이타 저장하기
        private void storeTraingData()
        {
            int[] faceID = { 1, 2, 4, 5 };//사실은 텍스트 파일에 같이 써야 하지만 분리하기 귀찮아서
            personNumTruthMat = new CvMat(1, nTrainFaces, MatrixType.S32C1, faceID);

            using (CvFileStorage fs = new CvFileStorage("facedata.xml", null, FileStorageMode.Write))
            using (CvMat eigen = new CvMat(1, nEigens, MatrixType.F32C1, eigenValMat))
            using (CvMat projected = new CvMat(nTrainFaces, nEigens, MatrixType.F32C1, projectedTrainFaceMat))
            {
                fs.WriteInt("nEigens", nEigens);
                fs.WriteInt("nTrainFaces", nTrainFaces);
                fs.Write("trainPersonNumMat", personNumTruthMat);
                fs.Write("eigenValMat", eigen);
                fs.Write("projectedTrainFaceMat", projected);
                fs.Write("avgTrainImg", pAvgTrainImg);

                for (int i = 0; i < nEigens; i++)
                {
                    String varName = String.Format("eigenVect_{0}", i);
                    fs.Write(varName, eigenVectArr[i]);
                }
                result = new IplImage(pAvgTrainImg.Size, BitDepth.U8, 1);
                //Currentley, bitmap converter can read not only BitDeth.U8 but also 32F
                Cv.CvtScale(pAvgTrainImg, result);
            }
        }
        #endregion

        #region PCA 인식

        public unsafe String[] recognize()
        {
            String[] str;

            int nTestFaces = 0; //비교할 이미지 숫자
            CvMat trainPersonNumMat; //학습으로 저장된
            float[] projectedTestFace;

            nTestFaces = loadFaceImgArray("test.txt"); //얼굴갯수 리턴
            projectedTestFace = new float[nEigens];

            if (!loadTranningData(out trainPersonNumMat)) return null;

            projectedTrainFaceMat = new float[trainPersonNumMat.Rows, trainPersonNumMat.Cols];//배열확보
            float[] tempProject = new float[nEigens];

            for (int i = 0; i < trainPersonNumMat.Rows; i++)
                for (int j = 0; j < trainPersonNumMat.Cols; j++)
                    projectedTrainFaceMat[i, j] = (float)Cv.mGet(trainPersonNumMat, i, j); //저장된 값 이동

            str = new String[nTestFaces]; //비교할 파일 갯수 만큼

            for (int i = 0; i < nTestFaces; i++)
            {
                int iNearest, nearest, truth;

                Cv.EigenDecomposite(faceImgArr[i], eigenVectArr, pAvgTrainImg, tempProject);

                iNearest = findNearestNeighbor(tempProject); //근접도
                truth = (int)Cv.mGet(personNumTruthMat, 0, i); //실제 명기된 ID
                nearest = (int)Cv.mGet(personNumTruthMat, 0, iNearest);

                str[i] = String.Format("nearest ID ={0}, Real ID = {1}", nearest, truth);

            }
            return str;


        }

        private int findNearestNeighbor(float[] projecTestFace)
        {
            double leastDistSq = 1e12;// DBL_MAX;
            int iTrain, iNearest = 0;

            for (iTrain = 0; iTrain < nTrainFaces; iTrain++) //비교할 얼굴 갯수
            {
                double distSq = 0;

                for (int i = 0; i < nEigens; i++)
                {
                    float d_i = projecTestFace[i] - projectedTrainFaceMat[iTrain, i];//학습 파일에서 읽은 값과
                    //distSq += d_i*d_i / eigenValMat->data.fl;  // 마할노비스 거리
                    distSq += d_i * d_i; // 유클리디안 거리
                }

                if (distSq < leastDistSq) //더 근접한 값이 있는지 찾음
                {
                    leastDistSq = distSq;
                    iNearest = iTrain;     //몇번째 얼굴인지
                }
            }
            return iNearest;
        }

        //저장된 학습 데이타 읽어 오기
        private bool loadTranningData(out CvMat pTrainPersonNumMat)
        {
            CvFileNode param;

            using (CvFileStorage fs = new CvFileStorage("facedata.xml", null, FileStorageMode.Read))
            {
                pTrainPersonNumMat = null;
                if (fs == null) return false;

                nEigens = fs.ReadIntByName(null, "nEigens");//고유치
                nTrainFaces = fs.ReadIntByName(null, "nTrainFaces"); //학습 갯수
                param = Cv.GetFileNodeByName(fs, null, "trainPersonNumMat");
                personNumTruthMat = fs.Read<CvMat>(param); //얼굴ID

                param = Cv.GetFileNodeByName(fs, null, "projectedTrainFaceMat");//학습된 값
                pTrainPersonNumMat = fs.Read<CvMat>(param);

                param = Cv.GetFileNodeByName(fs, null, "avgTrainImg"); //학습한 평균 이미지
                pAvgTrainImg = fs.Read<IplImage>(param);
                eigenVectArr = new IplImage[nEigens];
                for (int i = 0; i < nEigens; i++)
                {
                    String varName = String.Format("eigenVect_{0}", i);
                    param = Cv.GetFileNodeByName(fs, null, varName);
                    eigenVectArr[i] = fs.Read<IplImage>(param);
                }

            }
            int[] faceID = { 1, 2, 4, 5, 1, 2, 4, 5, 1, 2, 4, 5, 1, 2, 4, 5, 1, 2, 4, 5, 1, 2, 4, 5 };//사실은 텍스트 파일에 같이 써야 하지만 분리하기 귀찮아서
            personNumTruthMat = new CvMat(1, nTrainFaces, MatrixType.S32C1, faceID);//ID 배정

            return true;
        }
        #endregion
    }
}

 

- 해당 클래스가 정상 동작을 하기 위한 기초 첨부파일을 다운 받습니다

S1245_XML.zip
0.39MB

 

- 첨부파일의 내용을 Debug 폴더에 붙여 넣기 합니다

 

*첨부파일 내용

1) s1,s2,s4,s5 비교 그룹 이미지 (형식 : bpm)

   (샘플 얼굴 이미지 사진 입니다)

 

2) test.txt

   : 그룹에 포함되어 있는 파일 정보

 

3) train.txt

   : 그룹에 대표 이미지 지정

 

3) facedata.xml

   : 학습 정보 기록을 위한 xml

 

- 실행 한뒤 각 그룹 이미지 폴더에서 1.bpm을 불러와 검출을 시도합니다

 

[결과 창]

 

 

- 저는 샘플 사진으로 트와이스 맴버를 bpm으로 전환하여 비교 하여 다른 얼굴들과 어느정도 분석이 가능한지

  테스트를 해봤습니다(좋아하니깐!)

 

- 쯔위는 s5 그룹에 대표입니다

 

- 좌측 listBox1의 결과를 분석하면 해당 폴더의 그룹별 매칭 상태가 나타나는데 90%로 정도 쯔위를 판별해

  내는것을 볼수 있습니다

 

- 해당 자료를 구현하여 다른 샘플을 통해 다른 각도로 수정하여 응용해 보시기 바랍니다

 

반응형
반응형

안녕하세요

 

이번 포스팅에서는 OpenCvSharp 기능을 통해서 이미지속의 피부색을 검출하고 검출된 영역에

 

윤곽선을 표기하고 표시된 윤곽선 내부에 포함된 오목 부분을 추가 검출하여 손가락의 구분을 

 

나누어 보도록 하겠습니다

 

이번 포스팅도 OpenCvSharp 기능 구현 포스팅으로 처음 포스팅 내용과 이어지는 부분이

 

존재합니다

 

이해가 잘 되지 않으시다면 앞전 포스팅을 읽어보시고 보신다면 이해가 좀 더 빠를거 같아서

 

아래 OpenCvSharp의 처음 포스팅을 링크해 드리겠습니다

https://codingman.tistory.com/49

 

[C#]OpenCvSharp 라이브러리 사용하기 #1

안녕하세요 저번 포스팅에 C#으로 OpenCvSharp 라이브러리를 등록하여 구현하는 포스팅을 준비하던중에 OpenCv 3,4 버전에서 오류가 발생하는 문제가 있다는 얘길 듣고 부랴부랴 포스팅 내용을 검토해봤는데 역시..

codingman.tistory.com

[디자인]

- 메뉴버튼을 생성합니다

 

-생성한 메뉴에 클릭시 발생할 이벤트를 생성합니다

 

-생성된 클릭 이벤트 부분에 아래와 같이 코딩해줍니다

 

[Source Code]

        private void 피부색검출ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ConvextyDefect Cx = new ConvextyDefect();
            Cx.ConvextyDefectb();
        }

 

- 그다음 피부색 검출을 위한 기능 구현을 위해 클래스 파일을 생성합니다

   (클래스명칭은 ConvextyDefect.cs로 생성하였습니다.)

 

[Source Code]

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenCvSharp;
using OpenCvSharp.Blob;
using OpenCvSharp.CPlusPlus;
using OpenCvSharp.UserInterface;

namespace OpenCV_V1
{
    class ConvextyDefect
    {
        public void ConvextyDefectb()
        {
            using (IplImage imgSrc = new IplImage("hand.jpg", LoadMode.Color))
            using (IplImage imgHSV = new IplImage(imgSrc.Size, BitDepth.U8, 3))
            using (IplImage imgH = new IplImage(imgSrc.Size, BitDepth.U8, 1))
            using (IplImage imgS = new IplImage(imgSrc.Size, BitDepth.U8, 1))
            using (IplImage imgV = new IplImage(imgSrc.Size, BitDepth.U8, 1))
            using (IplImage imgBackProjection = new IplImage(imgSrc.Size, BitDepth.U8, 1))
            using (IplImage imgFlesh = new IplImage(imgSrc.Size, BitDepth.U8, 1))
            using (IplImage imgHull = new IplImage(imgSrc.Size, BitDepth.U8, 1))
            using (IplImage imgDefect = new IplImage(imgSrc.Size, BitDepth.U8, 3))
            using (IplImage imgContour = new IplImage(imgSrc.Size, BitDepth.U8, 3))
            using (CvMemStorage storage = new CvMemStorage())
            {
                //RGB -> HSV
                Cv.CvtColor(imgSrc, imgHSV, ColorConversion.BgrToHsv);
                Cv.CvtPixToPlane(imgHSV, imgH, imgS, imgV, null);
                IplImage[] hsvPlanes = { imgH, imgS, imgV };

                //피부색 영역을 구한다
                RetrieveFleshRegion(imgSrc, hsvPlanes, imgBackProjection);
                
                //최대의 면적의 영역을 남긴다
                FilterByMaximalBolb(imgBackProjection, imgFlesh);
                Interpolate(imgFlesh);

                //윤곽을 구한다
                CvSeq<CvPoint> contours = FindContours(imgFlesh, storage);
                if(contours != null)
                {
                    Cv.DrawContours(imgContour, contours, CvColor.Red, CvColor.Green, 0, 3, LineType.AntiAlias);

                    //요철을 구한다
                    int[] hull;
                    Cv.ConvexHull2(contours, out hull, ConvexHullOrientation.Clockwise);
                    Cv.Copy(imgFlesh, imgHull);

                    DrawConvexHull(contours, hull, imgHull);

                    //오목한 상태 결손을 구한다
                    Cv.Copy(imgContour, imgDefect);
                    CvSeq<CvConvexityDefect> defect = Cv.ConvexityDefects(contours, hull);
                    DrawDefects(imgDefect, defect);

                }
                using (new CvWindow("src", imgSrc))
                using (new CvWindow("back projection", imgBackProjection))
                using (new CvWindow("hull", imgHull))
                using (new CvWindow("defect", imgDefect))
                {
                    Cv.WaitKey();
                }
            }
        }

        ///<summary>
        ///백 프로젝션에 의해 피부색 영역을 구한다
        ///</summary>
        ///<param name="imgSrc"></param>
        ///<param name="hsvPlanes"></param>
        ///<param name="imgDst"></param>
        private void RetrieveFleshRegion(IplImage imgSrc, IplImage[] hsvPlanes, IplImage imgDst)
        {
            int[] histSize = new int[] { 30, 32 };
            float[] hRanges = { 0.0f, 20f };
            float[] sRanges = { 50f, 255f };
            float[][] ranges = { hRanges, sRanges };
            imgDst.Zero();
            using (CvHistogram hist = new CvHistogram(histSize, HistogramFormat.Array, ranges, true))
            {
                hist.Calc(hsvPlanes, false, null);
                float minValue, maxValue;
                hist.GetMinMaxValue(out minValue, out maxValue);
                hist.Normalize(imgSrc.Width * imgSrc.Height * 255 / maxValue);
                Cv.CalcBackProject(hsvPlanes, imgDst, hist);
            }
        }

        ///<summary>
        ///라벨링에 의해 최대 면적의 영역을 남긴다
        ///</summary>
        ///<param name="imgSrc"></param>
        ///<param name="imgDst"></param>
        private void FilterByMaximalBolb(IplImage imgSrc, IplImage imgDst)
        {
            CvBlobs blobs = new CvBlobs();

            imgDst.Zero();
            blobs.Label(imgSrc);
            CvBlob max = blobs.GreaterBlob();
            if (max == null)
            {
                return;
            }
            blobs.FilterByArea(max.Area, max.Area);
            blobs.FilterLabels(imgDst);
        }

        ///<summary>
        ///결손 영역을 보완한다
        ///</summary>
        ///<param name="img"></param>
        private void Interpolate(IplImage img)
        {
            Cv.Dilate(img, img, null, 2);
            Cv.Erode(img, img, null, 2);
        }

        ///<summary>
        ///윤곽을 얻는다
        ///</summary>
        ///<param name="img"></param>
        ///<param name="storage"></param>
        ///<returns></returns>
        private CvSeq<CvPoint> FindContours(IplImage img, CvMemStorage storage)
        {
            //윤곽 추출
            CvSeq<CvPoint> contours;
            using (IplImage imgClone = img.Clone())
            {
                Cv.FindContours(imgClone, storage, out contours);
                if(contours == null)
                {
                    return null;
                }
                contours = Cv.ApproxPoly(contours, CvContour.SizeOf, storage, ApproxPolyMethod.DP, 3, true);
            }

            //제일 긴 것 같은 윤곽만을 얻는다
            CvSeq<CvPoint> max = contours;
            for(CvSeq<CvPoint> c = contours; c != null; c=c.HNext)
            {
                if(max.Total < c.Total)
                {
                    max = c;
                }
            }
            return max;
        }

        ///<summary>
        ///ConvexHull 그리기
        ///</summary>
        ///<param name="contours"></param>
        ///<param name="hull"></param>
        ///<param name="img"></param>
        private void DrawConvexHull(CvSeq<CvPoint> contours, int[] hull, IplImage img)
        {
            CvPoint pt0 = contours[hull.Last()].Value;

            foreach(int idx in hull)
            {
                CvPoint pt = contours[idx].Value;
                Cv.Line(img, pt0, pt, new CvColor(255, 255, 255));
                pt0 = pt;
            }

        }

        ///<summary>
        ///ConvexityDefects 그리기
        ///</summary>
        ///<param name="img"></param>
        ///<param name="defect"></param>
        private void DrawDefects(IplImage img, CvSeq<CvConvexityDefect> defect)
        {
            int count = 0;
            foreach(CvConvexityDefect item in defect)
            {
                CvPoint p1 = item.Start, p2 = item.End;
                double dist = Getdistance(p1, p2);
                CvPoint2D64f mid = GetMidpoint(p1, p2);
                img.DrawLine(p1, p2, CvColor.White, 3);
                img.DrawCircle(item.DepthPoint, 10, CvColor.Green, -1);
                img.DrawLine(mid, item.DepthPoint, CvColor.White, 1);
                Console.WriteLine("No:{0} Depth:{1} Dist:{2}", count, item.Depth, dist);
                count++;
            }
        }

        ///<summary>
        ///2점간의 거리를 얻는다
        ///</summary>
        ///<param name="p1"></param>
        ///<param name="p2"></param>
        ///<returns></returns>
        private double Getdistance(CvPoint p1, CvPoint p2)
        {
            return Math.Sqrt(Math.Pow(p1.X - p2.X, 2) + Math.Pow(p1.Y - p2.Y, 2));
        }

        ///<summary>
        ///2점의 중점을 얻는다
        ///</summary>
        ///<param name="p1"></param>
        ///<param name="p2"></param>
        ///<returns></returns>
        private CvPoint2D64f GetMidpoint(CvPoint p1, CvPoint p2)
        {
            return new CvPoint2D64f
            {
                X = (p1.X + p2.X) / 2.0,
                Y = (p1.Y + p2.Y) / 2.0
            };
        }
    }
}

 

- "hand.jgp"파일은 해당 프로젝트의 Debug 폴더에 넣으시면 되고 예제 파일은 제가 사용한 파일을 업로드

 

하겠습니다

 

hand.JPG
0.03MB

 

- 이렇게 이미지 파일을 넣은 뒤 빌드하여 실행하시면 다음과 같은 결과가 나타나게 됩니다

 

[결과 창]

*원본이미지

* Back projection

 

*hull

 

*defect

반응형
반응형

안녕하세요

 

C# 컨텐츠로 블로그를 운영중인 코딩 연습생입니다

 

이번 포스팅에서는 C#으로 MSSQL를 접속하고 쿼리문을 전송시켜 연동시키기까지 한번 해보도록 하겠습니다

 

일반적인 방법으로는 

1) 접속정보 생성

2) SqlConnection 생성

3) SqlDataAdapter 생성

4) SqlCommand 실행

5) DataSet 실행

6) DataTable 데이터 받기

 

이런 순서로 직접 날코딩하여 사용을 했었습니다

 

그런데 프로젝트에서 DB 통신을 자주해야 하는경우 매우 귀찮아지게 됩니다

 

그래서 쉽게 MSSQL과 통신하고 내가 원하는 방식으로 FeedBack 받을수 있는 클래스 생성도 같이 설명해보

 

도록 하겠습니다

 

첫번째로 일반 방식입니다

string source = string.Empty;
string SYS_TIME = string.Empty;

//콜렉션 생성
DataRowCollection Rs2 = null;
//접속정보 생성
source = @"User Id=계정ID;Password=패스워드;Server=tjqjIP;Initial Catalog=DB명";

//컨넥션 생성
SqlConnection Con = new SqlConnection(source);
Con.Open();
SqlDataAdapter adapter = new SqlDataAdapter();
string query = "쿼리";
adapter.SelectCommand = new SqlCommand(query, Con);
DataSet ds = new DataSet();
adapter.Fill(ds);
DataTable table = ds.Tables[0];
Rs2 = table.Rows;

if (Rs2 != null && Rs2.Count > 0)
{
	for (int i = 0; i < Rs2.Count; i++)
	{
		//쿼리에서 FeedBack 받은 값 사용
        SYS_TIME = Rs2[0]["시간"].ToString();
	}
}
Con.Close();

 

단순한 SELECT문 하나 사용하더라도 참 많은 구문을 작성해야 합니다

 

두번째 방법으로는 클래스로 DB 명령를 미리 생성해놓고 호출하여 사용하는 방식으로 구현해 볼께요

1) DB에서 사용될 명령를 미리 생성합니다

   - Database.cs라는 구성 요소 클래스 파일 생성

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Data;
using System.Drawing;
using System.Windows.Forms;

namespace db_conn
{
    public partial class Database : Component
    {
        public Database()
        {
            InitializeComponent();
        }

        public Database(IContainer container)
        {
            container.Add(this);

            InitializeComponent();
        }

        private db_conn.BaseDB.DBTypeEnum m_DbType = BaseDB.DBTypeEnum.JDE;

        public db_conn.BaseDB.DBTypeEnum DbType
        {
            get { return m_DbType; }
            set { m_DbType = value; }
        }

        /// <summary>
        /// SELECT처럼 결과가 있는 쿼리를 실행한다
        /// </summary>
        /// <param name="query">쿼리</param>
        /// <returns>데이터테이블</returns>
        public DataTable ExcuteQuery(string query)
        {
            return ExcuteQuery(m_DbType.ToString(), query);
        }
        /// <summary>
        /// SELECT처럼 결과가 있는 쿼리를 실행한다
        /// </summary>
        /// <param name="dbName">DB명</param>
        /// <param name="query">쿼리</param>
        /// <returns>데이터테이블</returns>
        public DataTable ExcuteQuery(string dbName, string query)
        {
            db_conn.BaseDB db = BaseDB.GetDB(dbName.ToUpper());
            return db.ExcuteQuery(query);
        }
        /// <summary>
        /// insert, update처럼 조작하는 쿼리를 실행한다.
        /// </summary>
        /// <param name="query">쿼리</param>
        /// <returns>결과</returns>
        public int ExcuteNonQuery(string query)
        {
            return ExcuteNonQuery(m_DbType.ToString(), query);
        }
        // <summary>
        /// insert, update처럼 조작하는 쿼리를 실행한다.
        /// </summary>
        /// <param name="dbName">DB명</param>
        /// <param name="query">쿼리</param>
        /// <returns>결과</returns>
        public int ExcuteNonQuery(string dbName, string query)
        {
            db_conn.BaseDB db = BaseDB.GetDB(dbName.ToUpper());
            return db.ExcuteNonQuery(query);
        }
        /// <summary>
        /// 대량의 데이터를 인서트한다.
        /// </summary>
        /// <param name="toTbName">인서트할 테이블</param>
        /// <param name="dt">데이터테이블</param>
        /// <returns>오류메세지</returns>
        public string BulkInsert(string toTbName, System.Data.DataTable dt)
        {
            return BulkInsert(m_DbType.ToString(), toTbName, dt);
        }
        /// <summary>
        /// 대량의 데이터를 인서트한다.
        /// </summary>
        /// <param name="dbName">DB명</param>
        /// <param name="toTbName">인서트할 테이블</param>
        /// <param name="dt">데이터테이블</param>
        /// <returns>오류메세지</returns>
        public string BulkInsert(string dbName, string toTbName, System.Data.DataTable dt)
        {
            db_conn.BaseDB db = BaseDB.GetDB(dbName.ToUpper());
            return db.BulkInsert(toTbName, dt);
        }

        /// <summary>
        /// 1:1매칭되는 테이블을 넘겨 Dictionary로 받는다.
        /// </summary>
        /// <param name="dbName">DB명</param>
        /// <param name="query">쿼리(KEY_COL,VAL_COL이 반드시 있어야한다)</param>
        /// <returns>결과</returns>
        public Dictionary<string, string> GetDic1To1(string dbName, string query)
        {
            Dictionary<string, string> ret = new Dictionary<string, string>();
            DataTable dt = ExcuteQuery(dbName, query);
            string key = "";
            string val = "";
            for (int row = 0; row < dt.Rows.Count; row++)
            {
                key = dt.Rows[row]["KEY_COL"].ToString();
                val = dt.Rows[row]["VAL_COL"].ToString();
                if (!ret.ContainsKey(key))
                {
                    ret.Add(key, val);
                }
            }
            return ret;
        }
        /// <summary>
        /// 테이블을 넘겨 Dictionary(row)
        /// </summary>
        /// <param name="dbName">DB명</param>
        /// <param name="query">쿼리(KEY_COL은 반드시 있어야한다)</param>
        /// <returns>결과</returns>
        public Dictionary<string, DataRow> GetDicRow(string dbName, string query)
        {
            Dictionary<string, DataRow> ret = new Dictionary<string, DataRow>();
            DataTable dt = ExcuteQuery(dbName, query);
            string key = "";
            for (int row = 0; row < dt.Rows.Count; row++)
            {
                key = dt.Rows[row]["KEY_COL"].ToString();
                if (!ret.ContainsKey(key))
                {
                    ret.Add(key, dt.Rows[row]);
                }
            }
            return ret;

        }

        /// <summary>
        /// 데이터테이블을 딕셔너리에 넣는다.
        /// </summary>
        /// <param name="keyCols">키값을 가지는 컬럼들(:로 연결한다)</param>
        /// <param name="dt">넘길 테이블</param>
        /// <returns>결과</returns>
        public Dictionary<string, DataRow> GetDicRow(string keyCols, DataTable dt)
        {
            Dictionary<string, DataRow> ret = new Dictionary<string, DataRow>();

            string key = "";
            string[] spKeys = keyCols.Split(':');
            for (int row = 0; row < dt.Rows.Count; row++)
            {
                key = "";
                for (int i = 0; i < spKeys.Length; i++)
                {
                    key += dt.Rows[row][spKeys[i]].ToString();
                }
                if (!string.IsNullOrEmpty(key) && !ret.ContainsKey(key))
                {
                    ret.Add(key, dt.Rows[row]);
                }
            }
            return ret;
        }

        /// <summary>
        /// 데이터테이블을 딕셔너리에 넣는다.
        /// </summary>
        /// <param name="keyCols">키값을 가지는 컬럼들(:로 연결한다)</param>
        /// <param name="sumCols">SUM할 컬럼들(:로 연결한다)</param>
        /// <param name="dt">넘길 테이블</param>
        /// <returns>결과</returns>
        public Dictionary<string, DataRow> GetDicRow(string keyCols, string sumCols, DataTable dt)
        {
            Dictionary<string, DataRow> ret = new Dictionary<string, DataRow>();

            string key = "";
            string[] spKeys = keyCols.Split(':');
            string[] spSums = sumCols.Split(':');
            for (int row = 0; row < dt.Rows.Count; row++)
            {
                key = "";
                for (int i = 0; i < spKeys.Length; i++)
                {
                    key += dt.Rows[row][spKeys[i]].ToString();
                }

                if (!ret.ContainsKey(key))
                {   //INSERT
                    ret.Add(key, dt.Rows[row]);
                }
                else
                {   //UPDATE
                    for (int i = 0; i < spSums.Length; i++)
                    {
                        ret[key][spSums[i]] = Convert.ToDouble(ret[key][spSums[i]]) + Convert.ToDouble(dt.Rows[row][spSums[i]]);
                    }
                }
            }
            return ret;
        }

        /// <summary>
        /// 딕셔너리를 DataTable로 변환
        /// </summary>
        /// <param name="dic">딕셔너리</param>
        /// <returns>테이블</returns>
        public DataTable ConvertDicToDT(Dictionary<string, DataRow> dic)
        {
            DataTable dt = new DataTable();
            int cnt = 0;
            foreach (KeyValuePair<string, DataRow> pair in dic)
            {
                if (cnt == 0)
                {
                    dt = pair.Value.Table.Clone();
                }

                DataRow dr = dt.NewRow();
                for (int col = 0; col < pair.Value.ItemArray.Length; col++)
                {
                    dr[col] = pair.Value[col];
                }
                dt.Rows.Add(dr);

                cnt++;
            }

            return dt;
        }

    }
}

 

2) 접속 DB에 대한 속성 클래스 생성

   - BaseDB 클래스 파일 생성

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Reflection;
using System.Data.Common;

namespace db_conn
{
    
    public abstract class BaseDB 
    {
        #region 열거형
        /// <summary>
        /// 매출타입(OES/OEM)
        /// </summary>
        public enum DBTypeEnum
        {
            TEST            
        }
        #endregion

        private DBTypeEnum m_DBType = DBTypeEnum.TEST;

        public BaseDB(DBTypeEnum dbType)
        {
            m_DBType = dbType;
            
        }

        /// <summary>
        /// 쿼리를 실행한다(결과 있을때)
        /// </summary>
        /// <param name="query">쿼리</param>
        /// <returns>실행결과</returns>
        public abstract DataTable ExcuteQuery(string query);

        /// <summary>
        /// 쿼리를 실행한다(결과 없을때)
        /// </summary>
        /// <param name="query">쿼리</param>
        /// <returns>적용행수</returns>
        public abstract int ExcuteNonQuery(string query);


        /// <summary>
        /// 대량의 데이터를 Insert한다
        /// </summary>
        /// <param name="toTbName">저장할테이블</param>
        /// <param name="dt">데이터</param>
        /// <returns>에러메세지</returns>
        public abstract string BulkInsert(string toTbName, DataTable dt);

        /// <summary>
        /// DB연결자생성
        /// </summary>
        /// <returns>DB연결자</returns>
        protected abstract DbConnection DBConnection();

        

        /// <summary>
        /// SQL파일을 실행한다.
        /// </summary>
        /// <param name="path">SQL파일</param>
        /// <param name="args">인자(:)으로 구분</param>
        /// <returns>결과</returns>
        public DataTable ExcuteFileQuery(string path, string args)
        {
            string query = System.IO.File.ReadAllText(path);
            query = query.Replace("\r\n", " "); //강제개행
            query = query.Replace("\t", " "); //탭키
            query = query.Replace(";", " "); //탭키
            string[] spArgs = args.Split(':');
            for (int i = 0; i < spArgs.Length; i++)
            {
                query = query.Replace("{" + i.ToString() + "}", spArgs[i]);
            }
            return this.ExcuteQuery(query);
        }

        
        /// <summary>
        /// 줄리안데이트
        /// </summary>
        /// <param name="yyyymmdd">년월일</param>
        /// <returns>줄리안</returns>
        public int GetJulianDate(string yyyymmdd)
        {
            int yyyy = Convert.ToInt32(yyyymmdd.Substring(0, 4));
            int mm = Convert.ToInt32(yyyymmdd.Substring(4, 2));
            int dd = Convert.ToInt32(yyyymmdd.Substring(6, 2));
            DateTime lDate = new DateTime(yyyy, mm, dd);
            DateTime rDate = new DateTime(yyyy, 1, 1);

            string date1;
            string date2;
            date1 = "1" + yyyymmdd.Substring(2, 2);
            TimeSpan span = lDate.Subtract(rDate);

            date2 = Convert.ToString(Convert.ToUInt32(span.Days) + 1).PadLeft(3, '0');

            return Convert.ToInt32(date1 + date2);
        }

        public static BaseDB GetDB(string dbType)
        {
            BaseDB db = null;
            switch (dbType)
            {
                case "TEST":
                    db = new TEST();
                    break;
            }
            return db;
        }
    }
}

 

3) DB타입에 따른 세부 명령어 지정

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Data.Common;

namespace db_conn
{
    public class MssqlDB:BaseDB
    {
        public MssqlDB(string ip, string uid, string pwd, string db)
            : base(DBTypeEnum.MSSQL)
        {
            m_DB_IP = ip;
            m_DB_ID = uid;
            m_DB_PWD = pwd;
            m_DB_Name = db;
        }

        #region 멤버필드

        private string m_DB_IP = "";
        private string m_DB_ID = "";
        private string m_DB_PWD = "";
        private string m_DB_Name = "";

        #endregion

        #region 상수        
        private const string CN_DB_TIME = "600";    //300초까지 타임아웃한다.
        #endregion

        #region 공개메소드

        /// <summary>
        /// 대량의 DataTable을 인서트한다
        /// </summary>        
        /// <param name="toTbName">삽입할 테이블명</param>
        /// <param name="dt">데이터테이블</param>
        public override string BulkInsert(string toTbName, DataTable dt)
        {
            string ret = "";
            try
            {
                SqlBulkCopy bulk = new SqlBulkCopy(DBConnection().ConnectionString);
                bulk.DestinationTableName = toTbName;
                bulk.WriteToServer(dt);
                bulk.Close();
            }
            catch (Exception exLog)
            {
                ret = exLog.Message;
                throw new Exception(exLog.Message);

            }
            return ret;
        }

        /// <summary>
        /// 결과가 있는 쿼리를 실행
        /// </summary>
        /// <param name="query">쿼리</param>
        /// <returns>결과</returns>
        public override DataTable ExcuteQuery(string query)
        {
            DataTable dt = new DataTable();
            try
            {
                SqlDataAdapter adpt = new SqlDataAdapter(query, (SqlConnection)DBConnection());
                adpt.SelectCommand.CommandTimeout = Convert.ToInt32(CN_DB_TIME);
                adpt.Fill(dt);
            }
            catch (Exception eLog)
            {
                throw eLog;
            }
            return dt;
        }

        /// <summary>
        /// 결과가 없는 쿼리를 실행
        /// </summary>
        /// <param name="query">쿼리</param>
        /// <returns>영향받은 Row수</returns>
        public override int ExcuteNonQuery(string query)
        {
            int ret = 0;
            try
            {
                SqlConnection connect = (SqlConnection)DBConnection();
                connect.Open();
                SqlTransaction tran = connect.BeginTransaction();

                try
                {

                    SqlCommand com = new SqlCommand(query, connect, tran);
                    ret = com.ExecuteNonQuery();

                    tran.Commit();
                    connect.Close();
                }
                catch (Exception ineLog)
                {
                    tran.Rollback();
                    throw ineLog;
                }
            }
            catch (Exception eLog)
            {
                throw eLog;
            }
            return ret;
        }

        protected override DbConnection DBConnection()
        {
            string connectStr = "Server=" + m_DB_IP;
            connectStr = connectStr + ";" + "User ID = " + m_DB_ID;
            connectStr = connectStr + ";" + "Password = " + m_DB_PWD;
            connectStr = connectStr + ";" + "Initial Catalog = " + m_DB_Name;
            connectStr = connectStr + ";" + "Connection Timeout= " + CN_DB_TIME;
            SqlConnection ret = new SqlConnection(connectStr);
            return ret;
        }


        public int InsertUpdateImage(string _SQL, System.Drawing.Image _Image, string _ImageFieldName, System.Drawing.Imaging.ImageFormat _ImageFormat)
        {
            int _SqlRetVal = 0;

            try
            {
                SqlConnection con = (SqlConnection)this.DBConnection();
                con.Open();

                System.Data.SqlClient.SqlCommand _SqlCommand
                    = new System.Data.SqlClient.SqlCommand(_SQL, con);


                System.IO.MemoryStream _MemoryStream = new System.IO.MemoryStream();
                _Image.Save(_MemoryStream, _ImageFormat);


                System.Data.SqlClient.SqlParameter _SqlParameter
                    = new System.Data.SqlClient.SqlParameter("@" + _ImageFieldName, SqlDbType.Image);

                _SqlParameter.Value = _MemoryStream.ToArray();
                _SqlCommand.Parameters.Add(_SqlParameter);


                _SqlRetVal = _SqlCommand.ExecuteNonQuery();


                _SqlCommand.Dispose();
                _SqlCommand = null;
            }
            catch (Exception eLog)
            {
                throw eLog;
            }

            return _SqlRetVal;
        }

        #endregion

       
    }
}

 

이렇게 준비가 다 되시면 본문에서 DB 연결과 명령어 사용이 훨씬 간편해 집니다

 

[사용방법]

1. 사용하는 프로젝트에 빌드를 통해 생성된 구성요소클래스 파일을 참조에 넣어준다

 

2. 본문에서 db_conn을 사용하기 위한 선언문

 

3. 다음과 같은 형태로 DB 연동 사용

string SYS_TIME = string.Empty;

string Sql = " SELECT 시간";
       Sql += "  FROM A ";
TEST db = new TEST();
DataTable dt = db.ExcuteQuery(Sql);

if (dt.Rows.Count > 0)
{
	for (int i = 0; i <= dt.Rows.Count - 1; i++)
	{
		SYS_TIME = dt.Rows[i]["시간"].ToString());
	}
}

 

이렇게 하면 첫번째 방식과 동일한 결과 값을 얻을수 있습니다

 

가장 큰 차이점은 첫번째 방식은 쿼리를 종류 SELECT, INSERT, UPDATE, DELETE의 구문에 따라 방식이 조금 바뀝니다

 

그렇기 때문에 사용할때마다 코딩이 구문에 맞게 맞춰야하지요

 

하지만 두번째 방식의 경우 db의 변환 타입만 맞춰 사용하면 구문에 따른 코딩이 단순화가 된다는 점이 있습니다

 

두개 모두 구현하셔서 테스트 해보시기 바랍니다

 

감사합니다~

반응형

+ Recent posts