강좌,팁

[강좌:33] 컨트롤 배열 처리하기

조회 수 37563 추천 수 0 2006.09.28 17:37:58
허창원 *.19.45.37

송상욱님의 컨트롤 배열에 관한 질문을 받고나서, 제가 이용하고 있는 방법을 강좌로 만들어 보았습니다.

---------------------------------------------------------------------------------------

[강좌:33] 컨트롤 배열 처리하기

이용된 버전: LabWindows/CVI 7.1.1
강좌분류: KDManip.dll 활용, 따라하기 및 샘플예제

차례
서론
1. 이번 예제 프로그램의 개요
2. 작업준비
3. KDManip.dll(2006.8.31) 준비
4. 코딩
   4.1 변수, 함수 선언
   4.2 변수 초기화, 마무리 부분
   4.3 개별 컨트롤에 대한 처리
   4.4 값 적용의 일괄 처리
   4.5 Label 적용의 일괄 처리
4. 실행
마무리

 

서론
컨트롤 배열(Control Array)이라는 개념은 Visual Basic 같은 경우에는 언어와 개발툴 자체에 그러한 기능이 들어가 있습니다. 하지만 C/C++의 언어들은 엄연히 표준이 존재하고 있는 관계로 이러한 개념을 언어자체에 마음대로 포함하기는 곤란할 것입니다. 이런 경우 개발자가 적절히 프로그래밍하여 만들어 써야되겠지요.

컨트롤에 대한 배열 처리는 윈도 프로그래밍을 계속해 나오다 보면, 자연적으로 필요하게 됩니다.

비슷한 성격의 컨트롤이 여러개 있는데, 일일이 하나씩 그 동작을 기술해 준다든지, 배열에 들어 있는 값을 각각의 컨트롤에 표시하기 위해 소스코드 수준에서 일일이 각 컨트롤에 대해 기술한다는 것은 매우 비효율적인 일이 될 것입니다. 프로그래밍이란 게 어떻게 보면 자동화해나가는 과정이라고 볼 수 있는데, 프로그래밍 작업에 있어서도 보다 편리하게 해 나갈 필요가 있습니다.

컨트롤들을 배열처럼 처리하기 위해서는 컨트롤에 대한 ID를 배열로 저장해두는 것이 필요하고, 특정 컨트롤의 ID가 주어졌을 때, 컨트롤 배열의 몇 번째 element인지를 찾아내는 것이 필요하게 됩니다. 왜냐하면, 컨트롤 배열과 별도로 값에 대한 배열이 있고, 이 두 배열을 동기시키기 위해서는 배열의 index 정보가 공통으로 필요하기 때문이겠지요?

컨트롤 배열과 관련하여 제가 만들어 이용하는 C언어식의 객체가 있습니다. 컨트롤의 ID는 헤더파일에서 정수형 상수로 지정되기 때문에 정수형 데이터의 배열 관리를 위한 KDIntObj 라는 구조체를 이용하고 있습니다.(예전에 이용하던 형식을 최근(2006.8.31)에 수정하면서 만든 구조체입니다.) 이 구조체와 관련 함수들이 극동테크의 KDManip.dll(2006.8.31이후버전)에 포함되어 있으므로, 이번 강좌는 KDManip.dll의 활용에 관한 강좌로 볼 수 있습니다.

 

1. 이번 예제 프로그램의 개요
이번 따라하기 예제의 결과 프로그램 실행화면을 그림 1.1에 보였습니다.
컨트롤들의 값을 일괄변경하기 위한 부분, 컨트롤들의 Label을 일괄변경하기 위한 부분, 그리고, 컨트롤 각각의 값에 대한 처리와 표시부분으로 이루어져 있습니다.

그림 1.1 ComCallback 테스트 프로그램의 실행화면

그림 1.1의 입력값_0 ~ 입력값_4에 해당되는 수치 컨트롤에 값을 입력하고 엔터를 치면, 그 값을 gValue[] 라는 전역 배열의 해당 index에 그 값을 넣고, 그 값을 다시 표시용 수치 컨트롤과 LED 컨트롤에 그 결과를 반영합니다. 표시용 수치 컨트롤에는 입력된 값을 그대로 표시하고, LED에는 그 값이 5 이상이면 LED가 켜지도록 할 것입니다.

값을 일괄변경해보기 위해서 윗부분의 "값을 일괄변경"이라고 된 부분에 증가분 값을 넣은 다음, "적용" 버튼을 누르면, 입력값_0 컨트롤의 값을 기준하여 증가분만큼 더하여 다음 입력값_1 컨트롤에 세트(set)하게 됩니다. 이렇게 일괄 변경된 입력값들은 표시용 수치컨트롤과 LED에 반영됩니다.

"Label을 일괄변경" 부분에 문자열을 입력해주면, 그 문자열 값을 기준하여, 컨트롤의 Label을 일괄 변경시켜 줍니다.

이러한 일련의 과정이 컨트롤에 대한 배열처리를 하게 되어 소스코드가 깔끔해지게 됩니다.

2. 작업준비
작업 준비 과정은 "[강좌:21] CVI 프로그래밍 시작단계 정의(2)" 강좌 글의
"2. LabWindows/CVI의 프로그래밍 작업 시작단계" 부분에 따라 아래와 같이 간단히 정리합니다.

프로젝트 파일명: CtrlArray.prj

화면구성은 그림 2.1에 보였습니다.

그림 2.1 CtrlArray 프로젝트의 화면구성

uir 파일 내의 각 컨트롤의 속성은 표 2.1과 같이 설정합니다.

표 2.1 컨트롤의 속성값

컨트롤 종류 Constant Name Callback Function Label Default
Value
비고
Text Message

TEXTMSG
TEXTMSG_1
TEXTMSG_2
TEXTMSG_3
TEXTMSG_4
TEXTMSG_5

  해당없음

컨트롤 배열(Control Array) 테스트
그외 화면에 보이는 대로...

 

Numeric

numDelta

    0.0  
Command Button

cmdApplyInput

cmdApplyInput

적용 해당없음  
String

strInputLabel

strInputLabel

입력 입력  
String

strDispLabel

strDispLabel

표시 표시  
String

strLEDLabel

strLEDLabel

LED LED  
Numeric

numInput_0
numInput_1
numInput_2
numInput_3
numInput_4

numInput

입력 0.0  
Numeric

numDisp_0
numDisp_1
numDisp_2
numDisp_3
numDisp_4

 

표시 0.0 Control Mode: Indicator
LED

LED_0
LED_1
LED_2
LED_3
LED_4

 

LED    

 

Panel의 속성은 표2.2와 같이 설정합니다.

표 2.2 Panel의 속성설정

Panel 속성설정

Constant Name

PANEL

Callback Function

PanelCB

Panel Title

컨트롤 배열( Control Array) 테스트

Other Attributes

Sizable, Can Maximize를 uncheck

그리고, 기본 소스를 생성합니다. 기본으로 생성된 함수는 main() 함수와 PanelCB(), cmdApplyInput(), strInputLabel(),  strDispLabel(), strLEDLabel(), numInput()  콜백함수입니다.

3. KDManip.dll(2006.8.31) 준비
지금부터 이용할 라이브러리는 KDManip.dll 이고, 자료실(CVI정보나눔 자료실)에 업로드되어 있습니다. 아래의 이름으로 검색해보세요. (2006.8.31일 이후 버전이라야 됩니다.)

[라이브러리] KDManip.dll (2006.8.31버전)

그림 3.1에 다운로드받은 KDManip.dll 관련 파일들을 보였습니다. 실행시에는 dll 파일만 있으면 되지만, 프로그래밍할 때에는 헤더파일과 Import library가 모두 필요합니다.

그림 3.1 KDManip.dll 관련 파일

KDManip.lib 파일을 현재 프로젝트에 포함시키시고, KDManip.h도 필요시에 불러오기 쉽도록 프로젝트에 추가시켜 둡니다. 그림 3.2에 프로젝트 부분을 보였습니다.

그림 3.2 CtrlArray 프로젝트

그리고, CtrlArray.c 파일의 윗부분에 "KDManip.h"를 include 시켜둡니다.(그림 4.1에서 추가된 라인을 보였습니다.)

4. 코딩
이제 변수, 함수 선언부분, 변수 초기화 및 마무리 부분, 개별 컨트롤에 대한 처리, 값과 Label 적용의 일괄 처리 부분을 차례대로 소스와 함께 설명드리겠습니다.

4.1 변수, 함수 선언
그림 4.1에는 변수와 함수의 선언(declaration)부분을 보였습니다.

그림 4.1 변수, 함수 선언부분(CtrlArray.c)
(소스코드 이미지를 클릭하면 소스 텍스트 창이 나타난다는 거 아시죠?)

KDManip.h 파일에 선언된 구조체 중에 KDIntObj 라는 구조체가 있습니다. 그림 4.2에 선언부분만을 보였는데요, 구조체 변수의 선언과 함께 이후 절에서 설명되는 초기화, 마무리, AddItem(), FindIndex() 멤버 함수의 사용법만 알아두면 됩니다.

그림 4.2 KDIntObj 구조체 부분(KDManip.h, 참고만 하세요)

4.2 변수 초기화,  마무리 부분
그림 4.2에는 컨트롤 배열을 처리하기 위한 구조체 변수를 초기화하고, 마무리하는 부분을 보였습니다.

그림 4.2 구조체 변수 초기화, 마무리 부분(CtrlArray.c)

초기화 과정에서 컨트롤 배열로 이용할 컨트롤의 ID를 일일이 등록해 둡니다. 귀찮아도 어쩔 수 없구요, UIR 파일에서 컨트롤을 복사하여 붙여넣을 때마다 자동으로 번호를 붙여주는 데, 그렇게 컨트롤의 Constant Name이 차례대로 이름붙여져 있으면 번거로움이 상당히 줄어듭니다.

4.3 개별 컨트롤에 대한 처리
컨트롤 중에서 값을 입력 받는 수치 컨트롤(numInput_x)에는 공통의 Callback 함수가 지정되어 있습니다. numInput() 함수이지요. 그러면, 여러 입력용 수치 컨트롤 중에서 하나의 컨트롤에 값이 입력되면, 그것이 몇 번째 컨트롤인지, 그 index를 알아내는 것이 필요합니다. 그래야 해당 표시용 수치 컨트롤과 해당 LED에 그 값을 반영하게 되니까 말입니다.

이 numInput() 콜백함수의 소스를 그림 4.3에 보였습니다.

그림 4.3 구조체 변수 초기화, 마무리 부분(CtrlArray.c)

caInputNum 구조체 변수의 멤버함수를 호출하는 과정인데요, C++이라면 첫 번째 인자인 &caInputNum이 this 인자로 숨어서 넘어가겠지만, CVI는 C 문법만 지원하기 때문에, 해당 구조체 변수의 주소를 명시적으로 첫 번째 인자로 넘겨주도록 합니다.

numInput() 콜백함수의 두 번째 인자인 control은 현재 이벤트가 발생한 컨트롤의 ID가 넘어옵니다. 이 ID를 컨트롤 배열 구조체 내에서 찾아서 그 인자를 넘겨주는 멤버함수가 FindIndex()입니다.

이 index만 구하면, 해당 컨트롤의 값을 gValue[]라는 배열에 정확히 매칭시킬 수가 있습니다.

4.4 값 적용의 일괄처리
배열의 특성이 index만 바꾸어가면서 유사한 처리를 할 수 있다는 거 아니겠습니까? 그래서 이번에는 각 수치 입력 컨트롤의 값을 일괄적으로 증가시키거나 감소시키면서 값을 세팅해보는 처리입니다. 그림 4.4의 "적용" 버튼을 눌렀을 때의 처리 부분을 구현합니다.

그림 4.4 값을 일괄변경하기

이 "적용" 명령 버튼에 대한 콜백함수를 그림 4.5에 보였습니다.

그림 4.5 값을 일괄적으로 변경하고 적용하는 cmdApplyInput() 콜백함수(CtrlArray.c)

마지막에 호출된 Refresh_DisplayControl() 함수는 코멘트에 표시된 대로 gValue[] 배열의 값을 numDisp_x 컨트롤과 LED_x 컨트롤에 적용하는 역할을 합니다. 역시 컨트롤 배열 구조체를 이용하여 for 루프문으로 간단히 처리합니다. 그림 4.6에 Refresh_DisplayControl() 함수를 보였습니다.

그림 4.6 Refresh_DisplayContrl() 함수(CtrlArray.c)

4.5 Label 적용의 일괄 처리
컨트롤의 값뿐만 아니라 Label도 컨트롤 ID 배열 구조체에 의해 자동으로 처리할 수 있습니다.

그림 4.7 Label을 일괄 변경하기

입력, 표시, LED라고 이름붙여진 String 컨트롤에 문자열을 입력하고 엔터를 치면, 그 문자열이 기초가 되어 index가 붙여진 이름이 배열 컨트롤에 표시됩니다. 별도의 "적용" 명령 버튼을 두지 않았고, 각 String 컨트롤에 콜백함수를 지정해 두었습니다.

그림 4.8은 세 String 컨트롤의 콜백함수를 보였습니다.

그림 4.8 strInputLabel(), strDispLabel(), strLEDLabel() 콜백함수(CtrlArray.c)

각 콜백함수의 마지막 부분에 사용된 Refresh_Label() 함수는 배열 컨트롤의 Label을 일괄적으로 바꾸어 주는데, 첫 번째 인자의 값에 따라 0이면 입력용 수치 컨트롤, 1이면 표시용 수치 컨트롤, 2이면 LED를 갱신시켜 줍니다. 그림 4.9에 Refresh_Label() 함수를 보였습니다.

그림 4.9 Refresh_Label() 함수(CtrlArray.c)

5. 실행
별도로 설명을 드리지는 않았지만, PanelCB() Panel 콜백함수의 EVENT_CLOSE 이벤트 처리 부분에서 QuitUserInterface (0) 함수가 호출되도록 하십시오. 윈도의 닫기 버튼을 클릭했을 때, 프로그램을 종료시켜 줍니다. 이것은 2절의 작업준비 과정에서 소스코드를 생성할 때, 이미 QuitUserInterface() 함수가 호출되도록 하였을 것입니다. 만약 그렇게 안되었다면, 수동으로 넣어 주십시오.
이제 프로그램을 Build 한 후에, 실행을 해보겠습니다.
그림 5.1에는 CtrlArray 프로그램을 실행한 화면을 보였습니다.

그림 5.1 CtrlArray 프로그램의 실행화면

컨트롤 배열의 각 입력값을 개별적으로 넣어보기도 하시고, 값을 일괄적으로 증가시키도록 설정한 후 적용해 보시고, 또 Label도 일괄적으로 변경시켜 보세요.

잘 되지요? 만약 잘 안된다면, 설명한 것 중에서 빠트린 게 있으시든지, 아니면 제가 미처 설명드리지 못한 부분이 있든지 둘 중에 하나일 것 같네요...

마무리
컨트롤 배열을 처리하는 것을 KDManip.dll 내의 KDIntObj 구조체와 관련 함수들을 이용하여 구성해 해보았습니다. 이런 방식의 함수를 여러분들이 별도로 만들어서 사용해도 되겠습니다. 시간은 좀 걸리겠지만, 여러분 자신만의 좋은 라이브러리를 구축해 나갈 수가 있을 겁니다.

그것이 번거롭다면, KDManip.dll(2006.8.31버전)을 그대로 사용하십시오. 상용 프로그램 개발에 사용하여도 상관없습니다.

 

여러분들이 하시는 일이 영원히 가치있는 일에 쓰여지기를 바랍니다.

 

극동테크(www.kdtechno.com) 허창원 드림


야리싸내

2006.10.18 15:12:51
*.136.209.2

창원님...저거 cvi에서 구조체를 클래스 처럼 사용하는거 언제부터 됐나요?
아직도 6.0을 사용하는 야리라서요..^^;

허창원

2006.10.23 21:15:27
*.19.45.37

CVI에서 지원하는 것이 아니라 C언어 자체가 그게 되는 겁니다.
이러한 프로그래밍 스타일은 저도 어떤 영상보드 드라이버를 이용하다 보니 이런 방법이 맘에 들어 언제부턴가 거의 모든 데이터 구조에 이용하고 있습니다.
C++에 대한 향수가 늘 있어 왔는데, C++과 완전히 같지는 않아도 비슷한 형식으로 객체지향의 프로그래밍을 이용하고 있습니다.

구조체 선언 부분을 보시면, 대충 감이 잡히실 것 같은데요,
다음에 기회가 되면 다른 분들을 위해서도 간략화된 예제를 보이도록 해보겠습니다.

야리싸내

2006.11.01 21:42:10
*.136.209.2

거의 클래스이네요..^^
클래스형 구조체라고 하면 맞을것 같아요..^^

윤두봉

2007.06.21 08:39:44
*.155.122.239

궁굼한점이 있어서 그러는데요...
콜백함수 안에서 변수를 선언할때 어떻게 switch문 안에서 선언을 하죠?
함수내부에서 제일처음에 변수를 선언하지 않으면 에러가 나던데요.
switch문 안에서 선언하므로써 해당 컨트롤일때만 변수를 선언하면 메모리와 쓸데 없는 처리를 안할것같아서 이렇게 질문을 올려봅니다.

허창원

2007.09.21 17:08:10
*.97.72.14

switch 문 안이든 어디든, 블록의 시작 부분에서 선언하면 되죠....
변수 선언 바로 앞에 brace "{" 로 인해 새로운 블록이 시작되죠...
List of Articles
번호 제목 글쓴이 날짜 조회 수
96 [강좌:37] 테이블 셀로 파일을 드래그앤드롭하기 file [1] 허창원 2007-09-01 29829
95 [강좌:36] 테이블 셀에서 체크박스 기능 이용하기 file 허창원 2007-09-01 21092
94 [팁:17] 사용가능한 Com Port 찾기 file 허창원 2007-08-18 30816
93 [강좌:35] 엑셀(Excel) 파일에 출력하기(양식 유지한채로) [6] 허창원 2007-04-08 52099
92 [팁:16] 엑셀파일(xls)로 저장하기 [4] 허창원 2007-03-29 34519
91 [에러 최소화 습관 팁] 아직 나타내지 않은 Panel의 Control 값을 Set할 때 [1] 허창원 2006-11-25 26761
90 [팁:15] 엑셀에서 지원하는 파일(csv) 생성하기 [1] 허창원 2006-11-23 28922
89 [강좌:34] CVI의 최소화 기능 개선 [3] 허창원 2006-11-18 24287
88 [요약] [강좌:34] CVI의 최소화 기능 개선 허창원 2006-11-18 25896
» [강좌:33] 컨트롤 배열 처리하기 [5] 허창원 2006-09-28 37563
86 [강좌:32] 시리얼포트의 콜백함수를 만들어 이용하기 [2] 허창원 2006-08-25 33894
85 [강좌:31] 한글 IME, 위치로~~(강력추천) 허창원 2006-06-30 17792
84 [요약] [강좌:31] 한글 IME, 위치로~~(강력추천) [2] 허창원 2006-06-30 19811
83 [강좌:30] Panel을 마우스로 드래그하기(강좌29 업그레이드 버전) file 허창원 2006-06-29 12896
82 [요약] [강좌:30] Panel을 마우스로 드래그하기(강좌29 업그레이드 버전) 허창원 2006-06-29 15022
81 [강좌:29] 타이틀바 없는 Panel을 마우스로 드래그하기 [2] 허창원 2006-06-03 16932
80 [요약] [강좌:29] 타이틀바 없는 Panel을 마우스로 드래그하기 허창원 2006-06-03 15992
79 [팁:14] 프로그램 제거 단축아이콘 넣기(1차수정) [4] 허창원 2006-04-26 15297
78 [메모] 강좌의 종류를 분류해봅니다 [5] 허창원 2006-03-30 21274
77 [팁:13] 디버그 종료시에 뜨는 메시지 A non-debuggable thread... 방지 file [2] 허창원 2005-12-21 26576