AutoLISP 강좌 [6]


1. 입문(I) - AutoLISP의 기본 개념
2. 입문(II) - 사용자 정의 함수 제작
3. 입문(III) - 그 밖의 기본 기능들
4. 응용(I) - Entity와 Selection-Set
5. 응용(II) - Symbol table과 Device 제어
6. 응용(III) - Dialogue box 제어
7. 활용예제


6. Dialogue box 제어

이번호에서는 AutoCAD Release 12부터 지원되는 사용자 정의 다이얼로그 박스를 사용하여 도면상에 정의된 SYMBOL TABLE의 리스트를 보여주고 선택된 SYMBOL을 참조하는 엔티티를 삭제하거나 SYMBOL 정의 자체를 삭제하는 프로그램을 작성해 보겠다.

6.1 제어 프로그램의 기본 구성

다이얼로그 박스 제어 프로그램의 구성을 간단히 설명하면 다음과 같다.

(defun do-edit () <- 지정한 tile이 선택되었을 때 수행되는
  ...... CALL BACK 함수의 정의
)

(defun do-accept () <- 보통 OK 버튼을 선택한 경우 수행
  ...... <- 필요한 작업을 수행한다
  (done_dialog) <- 다이얼로그 박스를 종료
)

(defun main-dialog ( / dcl_id)
  (setq dcl_id (load_dialog "MAIN")) <- MAIN.DCL 파일을 로드한다.
  ; 파일로드에 실패하면 프로그램을 종료
  (if (not (new_dialog "main_box" dcl_id)) (exit))
  (set_tile "main_edit" "0") <- tile의 값을 설정
  ...... <- 또 다른 set_tile
  (mode_tile "main_but" 1) <- tile의 상태를 설정
  ...... <- 또 다른 mode_tile
  ; tile이 선택되었을 때 수행되는 함수 정의
  (action_tile "main_edit" "(do-edit)")
  ; OK 버튼이 선택된 경우
  (action_tile "accept" "(do-accept)")
  ...... <- 또 다른 action_tile
  (start_dialog) <- 다이얼로그 박스 실행
  (unload_dialog dcl_id) <- 로드된 다이얼로그 박스 정의를 제거
)

(defun C:MAIN ()
  ......
  (main-dialog) <- MAIN 프로그램내에서 다이얼로그 박스
  ...... 호출 함수를 수행한다.
)

위에서는 아주 간단한 예를 든 것이긴 하지만 대부분의 경우에도 이 이상 복잡해지지는 않는다. 그리고, DCL 파일이 원하는 형태로 나오는가를 확인하기 위해서는 다음과 같은 방법을 이용해 보자.

Command: (setq dcl_id (load_dialog "SYMBOL"))
1 <- 다이얼로그 박스의 ID
Command: (if (new_dialog "table_box" dcl_id) (start_dialog))

위와 같이 하면 다이얼로그 박스가 화면상에 나타나며 OK나 CANCEL 버튼을 누르면 종료될 것이다. 그리고, 마지막으로 다음과 같이 하여 로드된 다이얼로그 박스 정의를 제거하면 된다.

Command: (unload_dialog dcl_id)
nil

6.2 다이얼로그 박스의 구성

다이얼로그 박스의 구성을 보다 쉽게 이해하기 위해 먼저 프로그램을 수행해 보면서 아래 내용을 보기 바란다.
이 프로그램에서 사용될 다이얼로그 박스는 총 여섯개의 부분으로 구분해서 생각할 수 있다. 다음을 보자.

1) 다이얼로그 박스 자체
2) SYMBOL TABLE의 형태를 선택하기 위한 RADIO BUTTON
3) 일정한 패턴의 리스트를 만들기 위한 패턴 EDIT BOX
4) 패턴과 일치하는 리스트를 담을 LIST BOX
5) 리스트 박스를 통하지 않고 직접 이름을 입력할 수 있는 EDIT BOX
6) OK, CANCEL, ERROR tile
(ERROR tile은 초기에는 그냥 다이얼로그 박스 아래에 빈칸으로 나타난다.)

6.3 Radio Button 제어 (do-table 함수 참조)

라디오 버튼은 여러가지 항목들 중 하나만을 선택할 때 주로 사용되며 이번 예제에서는 삭제될 SYMBOL의 TABLE 형태를 선택하기 위해 사용된다.

라디오 버튼을 구성하는 형태는 테두리의 존재여부와 배열방향에 따라 다음과 같은 4가지 형식이 있으며 제어하는 방식은 동일하다.

* radio_column : 세로 배열

* radio_row : 가로 배열

* boxed_radio_column : 세로 배열, 테두리 및 제목

* boxed_radio_row : 가로 배열, 테두리 및 제목

먼저, DCL 파일에서 라디오 버튼 그룹 전체와 각각의 라디오 버튼 정의시에 키를 부여한다. 그런 다음 제어 프로그램에서는 선택된 버튼의 키를 얻어내어 그에 따른 처리를 수행하면 된다. 예제에서는 선택된 버튼의 키값을 통해 전역변수 #TABLETYPE의 값을 설정한 후 그 값에 따라 리스트 박스의 내용을 바꾸고 제목과 SYMBOL 삭제 함수도 변경하게 된다. 테이블의 형태에 따른 테이블의 이름, 제목, 버튼 키, 그리고 SYMBOL 삭제 함수는 전역변수 #TABLELIST에 정의되어 있으며 #TABLETYPE의 값으로 NTH 함수를 이용하여 얻어낼 수 있다.

DCL 파일에서...

table_box : dialog {
  ......
  : boxed_radio_column { <- 테두리가 있는 세로 배열
    label = "Table Type"; <- 라디오 버튼 그룹의 제목
    key = "type_but"; <- 라디오 버튼 그룹의 키
    : radio_button { <- 각각의 라디오 버튼 정의
      label = "Block"; <- 라디오 버튼의 제목
      mnemonic = "B"; <- 단축키 정의
      key = "block_but"; <- 라디오 버튼의 키
    }
    ...... <- 계속해서 라디오 버튼을 정의
  }
  ......
}

제어 프로그램에서...

(defun do-table ( / ret pat)
  ; 라디오 버튼 그룹에서 선택된 버튼의 키를 얻어낸다.
  (setq ret (get_tile "type_but"))
  ; 블럭을 선택한 경우 수행된다.
  (cond ((= ret "block_but") (setq #TABLETYPE 0))
    ...... <- 테이블 형태에 따라 수행되는 명령
  )
  ......
  ; 선택된 테이블에 따라 다이얼로그 박스의 제목을 바꾼다.
  (set_tile "table_title" ......)
  ; 항상 마지막에 선택했던 항목이 다음 사용시에
  ; 현재 선택 버튼으로 나타나게 하는 기능을 수행
  (mode_tile (caddr (nth #TABLETYPE #TABLELIST)) 2)
  ; 선택된 테이블에 따라 리스트 박스의 내용을 갱신
  (symbol-list "pat_list" ......)
  ; 선택된 테이블에 따라 SYMBOL 삭제함수를 변경
  (setq erase-table (eval (cadddr (nth #TABLETYPE #TABLELIST))))
)

......

  ; 다이얼로그 정의시에 라디오 버튼의 선택이 
  ; 변경되면 수행할 CALL BACK 함수를 정의
  (action_tile "type_but" "(do-table)")

......

6.4 List Box 제어

리스트 박스는 다이얼로그 박스를 구성하는 요소들 중 굉장히 처리하기 힘든 것 중에 하나가 아닐까 생각된다. 물론, AutoLISP에서는 별게 아닌지 모르지만 ADS로는 굉장히 까다로운 것임에 틀림없다. 따라서, AutoLISP을 통해 그 처리과정을 확실히 이해하는 것이 필요하리라 생각된다. 아래에서 지금 만들고자 하는 예제 프로그램에 사용되는 리스트 박스의 처리 방식에 대해 설명하기로 하겠다.

우선 두개의 전역변수를 선언하자. 하나는 선택된 SYMBOL의 이름을 담을 #SYMBOLNAME이고 또 다른 하나는 리스트 박스에 들어갈 SYMBOL들의 이름 리스트를 담을 #LBDATA이다. 그런 다음 리스트 박스에 들어갈 리스트를 정의하자.

1) 리스트 박스에 리스트 추가 (symbol-list 함수 참조)

간단하게 리스트 박스에 어떤 리스트를 담는 단계를 보면 다음과 같다.

  (start_list "pat_list") <- 리스트 박스에 내용추가 작업을 시작한다.

  (add_list "TEST1") <- 리스트 박스에 "TEST1"이라는 내용을 추가

  ...... <- 계속해서 리스트 박스에 내용을 추가

  (end_list) <- 리스트 박스 처리 작업을 종료한다.

이 프로그램에서는 현재 도면상에 존재하는 지정된 형태의 SYMBOL TABLE의 이름들을 담게 되므로 먼저 도면상에 존재하는 SYMBOL TABLE의 이름 중 주어진 패턴과 일치하는 이름을 찾아서 add_list로 추가시키고 이후에 어떤 리스트가 선택되었는가를 확인하기 위해 전역변수 #LBDATA에도 추가시킨다.

2) 선택된 항목 알아내기 (do-patlist 함수 참조)

  ; 리스트 박스상의 선택된 항목의 인덱스 번호를 얻어낸다.
  (setq in (get_tile "pat_list"))

  ; 인덱스 번호를 이용하여 전역변수 #LBDATA를 
  ; 참조하여 실제 리스트 내용을 얻어낸다.
  (setq in (nth (atoi in) #LBDATA))

  ; 임시적으로 SELECTION EDIT BOX 상에 선택된 내용을 지정한다.
  (set_tile "sel_edit" in)

3) 사용자가 직접 SYMBOL 명을 입력하는 경우 (do-select 함수 참조)

SELECTION EDIT BOX를 사용하여 사용자가 직접 SYMBOL 명을 입력하는 경우에는 입력된 SYMBOL 명이 실제로 존재하는가를 확인한다. 실제로 존재하면 #SYMBOLNAME을 입력된 SYMBOL 명으로 설정하고 존재하지 않으면 에러를 발생시킨다.

4) OK일때 처리 (do-accept 함수 참조)

OK 버튼이 선택되면 SELECTION EDIT BOX의 내용을 확인한 후 존재하지 않는 SYMBOL 명인 경우는 에러를 발생시키고, 프로그램을 계속 진행하며 존재하는 SYMBOL 명인 경우에는 다이얼로그 박스를 종료한다.

6.5 그외의 기법

1) 다이얼로그 박스의 타이틀을 바꾸고 싶을 때

다이얼로그 박스의 제목은 DCL 파일 내에서 label로 설정되지만 이것을 프로그램 수행중에 바꾸고 싶으면 DCL 파일의 dialog 항목에 key를 설정해 두고 제어 프로그램에서 값을 바꿔주면 된다.

DCL 파일에서...

table_box : dialog {

  key = "table_title";

  ......

}

제어 프로그램에서...

  ......
  (set_tile "table_title" "Layers Defined in this Drawing")
  ......

예제 프로그램에서는 이와 같은 방법으로 TABLE의 형태에 따라 다이얼로그 박스의 제목을 바꾸고 있다.

2) 다이얼로그 박스상에서의 ERROR 문 출력

버튼을 ok_cancel_err로 설정하면 OK와 Cancel 두개의 버튼이 생기고 밑부분에 한줄정도의 빈칸이 생긴다. 이 부분이 에러메시지가 써지는 부분인데 이 부분에 메시지를 쓰고 싶을 때는 "error" 키의 값에 필요한 메시지를 설정하기만 하면 된다.

DCL 파일에서...

table_box : dialog {

  ......

  ok_cancel_err;

}

제어 프로그램에서...

......

  (set_title "error" "Invalid LAYER name.")

......

3) SSGET 함수의 X 옵션 (erase-entity 함수 참조)

SSGET 함수의 X 옵션은 지정된 항목에 해당되는 엔티티들을 selection-set으로 만들어 주는 기능을 한다. 이때 만일 지정한 항목에 해당되는 엔티티가 하나도 없을 경우에는 nil을 반환하게 된다. 따라서, 그런 경우에 대한 처리 방법이 필요하다.

(if (setq ss (ssget "X" (list (cons 8 ln))))

  ; 선택된 엔티티들을 삭제한다.
  (command "ERASE" ss)

  ; 지정한 레이어를 참조하는 엔티티가 없음을 알려준다.
  (princ "\nUnreferenced LAYER.")

)

그리고, 예제 프로그램에서는 BLOCK, DIMSTYLE, LAYER, LTYPE, STYLE에 대해서는 실제로 SYMBOL TABLE 내에서 완전히 SYMBOL을 삭제하는 것이 아니라 위와 같이 그 SYMBOL을 참조하는 엔티티들만을 삭제한다. 따라서, 위의 함수 수행이후에 PURGE 함수를 수행하여 지정 테이블을 완전히 삭제하기 바란다.



관련 자료
disk [1] DELTABLE.LSP : 지정한 TABLE을 제거하는 프로그램
disk [2] SYMBOL.DCL : DELTABLE.LSP를 위한 DCL 파일

Last updated 2002-09-06 by choi@moon-sun.com
This page has been accessed : Counter times.
Home