IDL로 그래픽창이 두 개인 앱을 만들어봅시다

아시는 분들은 아시겠지만 IDL을 이용하여 소위 말하는 ‘앱’을 개발할 수 있습니다. IDL 세상에서는 위젯 프로그래밍(Widget Programming)이라고 합니다. 그래픽 유저 인터페이스(GUI)라고도 하죠. 물론 이러한 프로그래밍을 위해서는 어느 정도 공부가 필요합니다. 만약 이와 관련된 공부를 해야 할 경우 참고할만한 자료가 몇가지 있는데 소개해보면 다음과 같습니다.

1. IDL 도움말에서 왼쪽 탭의 메뉴구조상으로 Contents – IDL Programming – Interfaces (Widgets)라는 카테고리를 보면 관련된 내용이 소개되어 있습니다. 물론 영문입니다.

2. IDL User 웹사이트에서 문서자료실의 28번 게시물에 링크된 문서가 있습니다. 이 문서는 우리말로 되어 있으며, 제가 Widget Programming 교육을 할 때 사용하는 주교재와 거의 같다고 보면 됩니다.

3. (주)에스이랩에서 주관하는 Application Development 교육과정을 수강하는 방법도 있습니다. 물론 교육이 진행되는 시기를 감안해야 하는데, 2013년도 교육일정은 여기를 참조하면 됩니다.

오늘은 이러한 프로그래밍을 통하여 만들어볼 수 있는 간단한 예제로서 두 개의 그래픽창을 갖는 앱을 만들어보기로 하겠습니다. 비교적 간단한 예제이기는 하지만, 모든 과정을 세세하게 설명하기는 이런 게시물을 통해서는 쉽지 않습니다. 최대한 간략하게 소개하고 더 자세한 내용은 위에 소개한 내용을 참조하시기 바랍니다.

프로그램의 이름은 test_multi_draw_widget으로 정하였습니다. 먼저 그래픽창, 버튼 등으로 이루어진 GUI 요소들을 다음과 같이 만들어 전체적인 외형을 구성합니다.

여기서 tlb라는 이름으로 WIDGET_BASE라는 이름으로 만들어진 것이 가장 밑바탕이 되는 기반위젯(base widget)이 됩니다. 그래픽창은 두 개를 가로 방향으로 나란히 배치하고, 그 아래에 버튼 하나를 배치하려고 합니다. 이를 위하여 그래픽창 두 개를 위한 가로방향(ROW) 기반의 기반위젯인 dbase를 만들었고, 버튼을 위한 기반위젯인 bbase를 따로 만들었습니다. 그래픽창은 WIDGET_WINDOW라는 함수로 만들었습니다. 물론 이와 유사한 역할을 하는 WIDGET_DRAW라는 함수도 있습니다. 둘 사이의 차이는 WIDGET_DRAW는 기존의 Direct Graphics 기반의 그래픽창을 만들어주는 반면, WIDGET_WINDOW는 최근 도입된 New Graphics 기반의 그래픽창을 만든다는 것입니다. 구현하고자 하는 그래픽 표출이 어떤 그래픽 체계를 기반으로 할 것이냐에 따라 선택적으로 사용하면 됩니다. 일단 NG 기반으로 먼저 설명을 하겠습니다.

외형적인 구성요소들은 다 만들었으므로, 다음 단계에서는 WIDGET_CONTROL 명령을 사용하여 실제로 우리 눈에 보이게끔 ‘구현(Realize)’을 합니다. 그리고 두 그래픽창 위젯 각각에 대한 고유식별번호를 가져옵니다.

여기서는 각 그래픽창 위젯에 대하여 GET_VALUE 키워드를 사용하여 고유번호를 가져왔습니다. 이 고유번호들은 나중에 이벤트 처리 루틴에서 반드시 필요합니다. 이벤트 처리 루틴은 서브루틴의 형태로 나중에 따로 만들 것입니다. 우선은 나중에 이 서브루틴으로의 전달을 위하여 전달 가능한 형태로 교환용 정보를 구성해야 하는데, 대개 다음과 같이 구조체(Structure)의 형태를 주로 사용합니다.

물론 이러한 프로그래밍 세계에서는 구조체외에도 포인터(Pointer), 리스트(List), 해쉬(Hash) 등의 데이터 형태를 사용하는 경우도 있지만, 여기서는 그냥 구조체를 사용하는 방식으로 한정짓겠습니다. 구조체가 뭐냐에 대해서는 설명하자면 또 길어질텐데, 위에서 소개한 우리말 문서에 이에 관한 내용도 있으므로 참조하시기 바랍니다. 그리고 이렇게 구조체의 형태로 구성한 교환정보를 tlb의 User Value로 집어넣었습니다. 이렇게 넣어두면 나중에 이벤트 처리루틴에서 다시 끄집어내어 사용할 수 있게 됩니다.

현재 우리의 목표는 하단의 버튼을 누르면 그래픽창 둘 중 한군데에서 원하는 그림이 표출되도록 하는 것입니다. 여기서 ‘버튼을 누른다’는 동작은 하나의 이벤트입니다. 즉 외형만 있는 죽은 앱이 아닌, 사용자의 입력에 따라 뭔가 반응을 하는 살아있는 앱이 되도록 하려면, 이러한 이벤트 처리가 가능하도록 프로그래밍되어야 합니다. 따라서 메인루틴의 맨 끝부분에는 다음과 같이 XMANAGER라는 명령이 들어가야 합니다. 그래야 버튼을 누르는 등의 사용자에 의한 조작이 있을 경우, 이와 관련된 정보를 이벤트 처리루틴으로 전달하는 체계가 활성화됩니다.

이제 메인루틴의 구성은 다 끝났습니다. 그 다음에는 이벤트 처리루틴을 만들어줘야 합니다. 여기서는 하나의 이벤트 처리루틴을 사용할 것인데, 그 이름은 사실 앞에서 이미 정해놓았습니다. 그 이름은 메인루틴의 다음 문구에 나와있습니다.

여기서 WIDGET_BUTTON 함수의 EVENT_PRO라는 키워드에 명시된 ‘show_image’가 바로 그 이름입니다. 이 의미는 버튼을 누르는 이벤트가 발생하면 그 이벤트 관련정보를 show_image라는 이름의 이벤트 처리루틴으로 보내란 의미입니다. 실제로 이벤트 관련정보는 이벤트 구조체의 형태로 구성되어 처리루틴으로 전달됩니다. 이벤트 처리루틴은 다음과 같이 만들어보았습니다.

여기서 맨 처음에 사용된 WIDGET_CONTROL 명령의 대상은 event.TOP으로 되어 있는데, 이는 이벤트를 발생시킨 위젯의 가장 근본이 되는 위젯을 가리킵니다. 여기서는 메인루틴에서 정의했던 tlb를 뜻합니다. GET_UVALUE 키워드는 여기에 부여되었던 User Value를 끄집어내란 의미입니다. 그리고 이벤트 처리루틴내에서 이 정보를 info라는 이름으로 인식시킨 것입니다. 이제는 이벤트 처리루틴내에서도 info의 내용을 꺼내어 활용할 수 있게 되었습니다.

그래서 만약 버튼을 눌렀을 때 첫번째 그래픽창에서 그림이 표출되도록 프로그램밍을 하고자 한다면, 이 그래픽창의 고유번호를 가져와서 이 그래픽창을 활성화시키면 되는데, 그 역할을 하는 명령이 info.wid1.Select입니다. 이 상태에서는 그림을 그리면 이 그래픽창으로 표출됩니다. 다만 NG체계의 특성상 그래픽 함수내에서 /CURRENT 키워드를 사용해야 현재 활성화된 그래픽창에 표출이 된다는 점은 유념해야 합니다.

어쨌든 이와 같은 내용으로 구성된 전체적인 프로그램의 내용은 아래와 같습니다. 물론 이 내용을 test_multi_draw_widget.pro라는 파일로 저장하고 컴파일 및 실행을 해야 합니다.

이 프로그램을 실행하여 하단의 ‘Press Me’ 버튼을 눌러 첫번째 그래픽창에 그림을 표출한 모습은 다음 그림과 같습니다.

NG체계의 그래픽창 두 개로 이루어진 GUI의 모습

NG체계의 그래픽창 두 개로 이루어진 GUI의 모습

만약에 그래픽창을 NG 기반이 아닌 DG 기반으로 만들고자 한다면 몇 줄의 내용이 이에 맞게 바뀌어야 합니다. 바뀐 부분은 오른쪽에 ‘DG’라는 주석을 달아 표시해보았습니다.

여기서는 WSET이라는 명령을 사용하여 원하는 그래픽창을 활성화시켰다는 점을 유념하면 됩니다. 이 상태로 실행한 모습은 다음 그림과 같습니다.

DG체계의 그래픽창 두 개로 이루어진 GUI의 모습

DG체계의 그래픽창 두 개로 이루어진 GUI의 모습

결국 버튼을 눌렀을 때 그림이 표출될 위치를 두 그래픽창들 중 어느 쪽으로 할 것이냐는, 이벤트 처리루틴내에서 wid1, wid2 중 어느 것을 활성화시키느냐로 결정하면 됩니다. 어쨌든 지금 소개한 예제는 그래픽창을 갖는 IDL GUI의 아주 단순한 예입니다. 이보다 더 많은 기능을 갖는 복잡한 GUI의 제작도 물론 가능하지만, 아무래도 그만큼 신경써야할 부분도 많고 시간도 좀 걸릴 수 밖에 없습니다. 하지만 IDL로 보다 다양한 방식의 프로그래밍이 가능하다는 것을 이러한 예제를 통하여 확인할 수 있지않나 합니다.