TCL/TK 문법 (2)

서버관련지식 : 2007. 4. 29. 15:33
반응형

9.  Tk 기초

○ Tk는 윈도우 프로그래밍을 위한 툴킷이다.

○ Tk는 X 윈도우 시스템을 위해 디자인되었지만 매킨토시와 MS-Windows에도 포팅되었다.

○ Tk는 widget을 생성하고 관리할 수 있는 Tcl 명령들을 제공한다.

○ widget은 GUI에서 어떤 특정한 모양과 동작을 가지는 윈도우를 지칭한다.

○ widget과 window라는 용어는 자주 혼용되어 사용된다.

○ widget 형태에는 버튼, 스크롤바, 메뉴, 텍스트 윈도우 등이 포함된다.

○ Tk는 또한 일반적으로 그림을 그리는 데 사용되는 캔버스라는 widget을 제공한다.

○ X 윈도우 시스템은 윈도우의 계층적인 구성을 지원하는데, Tk도 이러한 특성을 따른다.

○ 응용 프로그램에서 윈도우의 계층 구조라는 것은 하나의 메인 윈도우가 있으며 그 안에 여러 개의 자식 윈도우가 포함된다는 것을 의미한다.

○ 자식 윈도우도 또한 그 안에 여러 윈도우를 포함할 수 있다.

○ UNIX 파일 시스템에서 디렉토리가 다른 디렉토리와 파일을 포함하는 데 사용되는 것과 마찬가지로 윈도우의 계층 구조에서도 윈도우는 다른 윈도우를 포함하는 데 사용될 수 있다.

○ widget은 형상 관리자(geometry manager)에 의해 그 크기와 위치가 조절된다.

○ 형상 관리자가 widget에 대해 알게 되기 전에는 widget은 화면에 나타나지 않는다.

○ Tk에서는 여러 가지 형상 관리자를 사용할 수 있다.

○ 본 교재에서는 주로 packer 형상 관리자를 사용한다.

○ 형상 관리자에서 잘 사용되는 기법은 프레임 widget을 다른 widget을 포함하는 데 사용하는 것이다.

○ 하나 이상의 widget이 생성되고 프레임 widget에 형상 관리자에 의해 배치된다.

○ Tk를 사용해 만든 프로그램은 이벤트에 의해 동작하게 된다.

○ 이벤트는 bind명령을 통해 Tcl 명령과 연결된다.

○ X 프로토콜에 의해 정의된 이벤트에는 키보드와 마우스 입력을 포함한 여러 가지가 있다.

○ Tk widget은 기본적인 이벤트 처리기를 내장하고 있으므로 모든 사항을 프로그래밍할 필요는 없다.

○ 이벤트 바인딩은 전역 바인딩, 클래스 바인딩, 인스턴스 바인딩으로 나뉜다.

○ 클래스의 예로 모든 버튼을 나타내는 Button을 들 수 있다.

○ Tk 툴킷은 Button 클래스와의 바인딩을 통해 버튼에 대한 동작을 정의하는 기본 바인딩을 제공한다.

○ 프로그래머는 새로운 바인딩 그룹을 만들고 여러 바인딩을 묶을 수 있다. bindtags 명령은 바인딩 그룹을 관리하고 우선 순위를 정한다.

○ 바인딩과 관련된 개념으로 포커스(focus)를 들 수 있다.

○ 어떤 때에도 하나의 widget은 입력 포커스를 가지고 있으며 그 widget으로 키보드 입력이 전달된다.

○ 포커스를 주는 방법에는 두 가지가 있는데, 하나는 마우스 포인터 바로 밑에 있는 widget에게 포커스를 주는 것이며 또 하나는 직접 특정 widget에게 포커스를 주는 것이다.

○ Tk는 포커스를 바꿀 수 있는 명령을 제공한다.

○ Tk 스크립트는 widget을 생성하고 형상 관리자를 사용해 widget들을 배치하며 widget에 대한 action을 정의하는 구조로 이루어진다.

○ wish를 소스 프로그램의 이름 없이 그냥 실행시키면 기본적으로 빈 메인 윈도우를 하나 생성한 후 명령 라인 프롬프트를 보여 준다.

 


9.1.  Hello, World

○ 먼저 간단한 Tk 응용 프로그램을 짜 보도록 한다.

○ 버튼을 누르면 표준 출력에 "Hello, World!"라는 글자를 출력해 준다.

○ Hello, World 스크립트는 버튼을 생성하고 버튼을 배치하는 두 부분으로 구성된다.

○ 그림 10-1은 이 스크립트의 실행 화면을 보여 준다.

 

그림 10-1). Hello World 실행화면


#!/usr/local/bin/wish

button .hello -text Hello \

      -command {puts stdout "Hello, World!"}

pack .hello -padx 20 -pady 10

○ 첫 번째 줄은 다른 UNIX 명령과 똑같은 방식으로 수행하기 위해 필요한 줄이다.

○ 이 줄은 윈도우즈 등의 시스템에서 수행하는 경우는 필요없다.

○ button 명령은 button을 생성한다.

button .hello -text Hello \

      -command {puts stdout "Hello, World!"}

=>.hello

○ 버튼의 이름은 .hello이다.

○ 버튼에 쓰여질 글자는 Hello이다.

○ 버튼과 연결된 명령은 다음 명령이다.

puts stdout "Hello, World!"

○ pack 명령은 버튼을 화면에 보여 준다.

○ Tk는 widget을 생성하고 이름을 붙일 때 객체 기반 시스템을 사용한다.

○ 각 widget 클래스는 그 클래스의 widget의 한 인스턴스를 생성하는 명령과 연결되어 있다.

○ 새로운 widget이 생성되면 새로운 그 인스턴스와 연결될 새로운 Tcl 명령이 정의된다.

○ 위의 예제에서 만든 버튼은 .hello라는 이름을 사용해 접근할 수 있다.

○ .hello 버튼이 잠시동안 깜빡거리게 하고 싶은 경우는 다음 명령을 수행한다.

.hello flash

○ 버튼과 연결된 명령을 수행하기 위해서는 다음 명령을 수행한다.

.hello invoke

=> Hello, World!

 


9.2.  Tk widget에 이름 붙이기

○ 버튼의 이름 앞에 붙은 점 기호는 필요하다.

○ Tk는 widget의 이름이 widget 계층 구조에서의 위치를 반영할 수 있도록 하고 있다.

○ 계층 구조의 루트는 메인 윈도우이며 그 윈도우의 이름은 ‘.’이다.

○ 이것은 UNIX의 파일 시스템에서 ‘/’가 루트 디렉토리를 나타내는 동시에 디렉토리 이름을 구분하기 위해 사용되는 것과 유사하다.

○ Tk는 UNIX 파일 시스템에서의 '/'와 비슷한 용도로 '.'을 사용한다.

○ .hello라는 widget은 메인 윈도우의 자식 윈도우를 나타내는 이름이다.

○ .hello라는 widget의 자식 윈도우를 만들고 싶다면 그 윈도우의 이름은 .hello.hi의 형식으로 하면 될 것이다.

○ Tk 경로명은 항상 소문자나 숫자로 시작해야 한다.

○ 이러한 Tk의 이름 붙이는 방법에는 한 가지 큰 단점이 있다.

○ 단점은 어떤 widget을 widget 계층 구조의 다른 위치로 옮기고 싶은 경우에는 widget의 이름을 바꾸어야 한다는 것이다.

○ 이러한 문제를 해결하기 위해서는 직접 widget의 이름을 사용하지 말고 widget의 이름을 담는 변수를 사용하는 것이 좋다.

 


9.3.  Tk widget의 설정

○ Hello, World! 예제에는 Tk widget의 속성을 바꾸는 방법이 소개되어 있다.

○ widget의 속성 이름은 -로 시작한다.

○ -로 시작하는 속성 이름 다음에 오는 파라미터가 그 속성의 속성값이 된다.

○ 간단한 widget은 10개 내외의 속성을 가지며 복잡한 widget의 경우는 20개 이상의 속성을 가진다.

○ 이러한 속성값에는 기본값이 주어여 있으므로 그 중 필요한 일부의 속성만을 변경하면 된다.

○ 각 widget 인스턴스는 속성을 얻어 내고 바꿀 수 있는 configure(줄여서 config라고도 쓸 수 있음)라는 연산을 지원한다.

○ config 명령의 문법은 widget을 생성할 때 주는 속성과 똑같은 파라미터를 준다.

○ 예를 들어 .hello 버튼의 배경 색을 빨간색으로 바꾸고 싶은 경우는 다음 명령을 수행하면 된다.

.hello config -background red

○ config 연산은 현재의 속성 값을 얻어내는 데에도 사용할 수 있다.

.hello config -background

=> -background background Background #ffe4c4 red

○ 리턴값은 명령행 옵션, 자원의 이름, 클래스 이름, 기본값, 그리고 현재 값이 포함되어 있다.

○ 클래스와 리소스 이름은 X 윈도우의 자원 관리 메커니즘과 관계가 있다.

○ 보통은 현재 값만이 필요하다.

○ 현재의 값만을 얻어내기 위해서는 cget 연산을 수행하면 된다.

.hello cget -background

=> red

○ widget 속성은 언제라도 바꿀 수 있다.

○ 다음 명령은 .hello widget 버튼을 Goodbye! 버튼으로 바꾼다.

.hello config -text Goodbye! -command exit

 


9.4.  Tk widge 속성과 X 자원

○ widget의 속성에 이름을 붙이는 방법에는 명령행 옵션, 이름, 클래스의 세 가지가 있다.

○ 명령행 옵션은 Tcl에서 사용하는 방법이다.

○ 명령행 옵션은 소문자이며 - 기호로 시작한다.

○ 이름과 클래스로 widget 속성에 이름을 붙이는 것은 X 윈도우즈 시스템의 자원 명세서와 관련이 깊다.

○ 속성에 해당하는 자원의 이름은 앞에 - 기호가 붙지 않으며 이름의 중간중간에 대문자가 들어가기도 한다.

○ 자원 클래스는 대문자로 시작하며 중간에 대문자가 들어간다.

○ X에서는 이와 같은 이름 붙이는 방법들을 사용해 미리 정의된 widget 속성에 이름을 붙여 두었으므로 이름 붙이는 법을 잘 알아두는 것이 편리하다.

○ 보통 Tk와 함께 man page가 따라오는 것이 보통이므로 이러한 man page를 참조하는 것이 좋다.

% man button

 


9.5.  Tk 명령 종합

○ 다음은 Tk에서 widget을 만들기 위해 사용하는 명령들이다.

- button: 버튼을 생성한다.

- checkbutton: Tcl 변수와 연결된 토글할 수 있는 버튼을 만든다.

- radiobutton: 여러 개의 radio button 중에서 하나를 택할 수 있다.

- menubutton: 메뉴를 부르는 버튼을 만든다.

- menu: 메뉴를 생성한다.

- canvas: 캔버스를 만든다.

- label: 텍스트 레이블을 만든다.

- entry: 한 줄의 입력을 받을 수 있는 widget을 생성한다.

- message: 읽을 수만 있는 여러 줄의 텍스트 메시지를 생성한다.

- listbox: 리스트 박스를 만든다.

- text: 범용의 텍스트 widget을 만든다.

- scrollbar: 다른 widget과 연결되는 스크롤 바를 만든다.

- scale: 어떤 변수의 값을 설정할 때 사용되는 scale widget을 만든다.

- frame: 형상 관리자와 함께 사용되 다른 widget을 포함하는 데 사용되는 프레임 widget을 만든다.

- toplevel: X 윈도우의 새로운 top-level 프레임을 만든다.

다음은 widget들을 다루는 여러 명령들이다.

- after: 얼마간의 시간이 지난 후에 특정 명령을 수행한다.

- bell: X 벨 장치를 통해 벨을 울린다.

- bind: Tcl 명령을 X 이벤트에 연결한다.

- bindtags: 바인딩 클래스를 생성하고 바인딩 상속을 제어한다.

- clipboard: X 클립보드를 다룬다.

- destroy: widget을 없앤다.

- fileevent: Tcl 명령을 file descriptor와 연결시킨다.

- focus: 입력 포커스를 조절한다.

- grab: 다른 widget으로부터 입력 포커스를 빼앗아 온다.

- image: 이미지를 생성하고 다룬다.

- lower: 윈도우의 스택 순서에서 윈도우를 밑으로 보낸다.

- option: Xresources 데이터베이스에 접근한다.

- pack: 화면에 widget들을 배치해 보여 준다.

- place: 화면에 위치를 주어 widget을 배치한다.

- raise: 윈도우의 스택 순서에서 윈도우를 위로 올린다.

- selection: X PRIMARY selection을 다룬다.

- send: Tcl 명령을 다른 Tk 응용에게 전송한다.

- tk: 응용 프로그램의 이름을 묻거나 설정한다.

- tkerror: 에러를 처리한다.

- tkwait: 어떤 이벤트의 발생을 기다린다.

- update: 이벤트 루프를 통해 화면을 갱신한다.

- winfo: 윈도우의 상태에 대해 질의한다.

- wm: 윈도우 메니저와 상호 정보교환을 한다.

 

 

 

10.  예제로 배우는 Tk

○ Tk는 쉽고 재미있게 사용자 인터페이스를 만들 수 있게 해 준다.

○ 본 절에서는 Tk로 어떤 일들을 할 수 있는지를 살펴 보는 데 주안점을 둔다.

 


10.1.  ExecLog

○ 첫 번째로 살펴 볼 프로그램은 UNIX 프로그램을 수행할 수 있는 간단한 사용자 인터페이스를 제공한다.

○ 사용자 인터페이스는 'Run it'과 'Quit'의 두 버튼, 명령을 입력 받는 entry widget, 그리고 수행된 프로그램의 로그를 기록하는 텍스트 widget으로 구성된다.

○ 이 스크립트는 프로그램을 파이프라인으로 수행하며 출력을 기다리기 위해 fileevent 명령을 사용한다.

○ 이러한 구조는 프로그램이 수행 중인 경우라도 사용자 인터페이스가 동작하도록 해 준다

○ 그림 10-2와 다음 예제는 ExecLog 프로그램의 실행예와 소스 코드이다.

 

그림 10-2). ExecLog 프로그램의 실행예


#!/usr/local/bin/wish -f

# execlog - run a UNIX program and log the output

# Set window title

wm title . ExecLog

 


# Create a frame for buttons and entry

frame .top -borderwidth 10

pack .top -side top -fill x

 


# Create the command buttons

button .top.quit -text Quit -command exit

set but [button .top.run -text "Run it" -command Run]

pack .top.quit .top.run -side right

 


# Create a labeled entry for the command

label .top.l -text Command: -padx 0

entry .top.cmd -width 20 -relief sunken \

      -textvariable command

pack .top.l -side left

pack .top.cmd -side left -fill x -expand true

 


# Set up key binding equivalents to the buttons

bind .top.cmd <Return> Run

bind .top.cmd <Control-c> Stop

focus .top.cmd

 


# Create a text widget to log the output

frame .t

set log [text .t.log -width 80 -height 10 \

      -borderwidth 2 -relief raised -setgrid true \

      -yscrollcommand {.t.scroll set}]

scrollbar .t.scroll -command {.t.log yview}

pack .t.scroll -side right -fill y

pack .t.log -side left -fill both -expand true

pack .t -side top -fill both -expand true

 


# Run the program and arrange to read its input

proc Run {} {

      global command input log but

      if [catch {open "|$command |& cat"} input] {

              $log insert end $input\n

      } else {

              fileevent $input readable Log

              $log insert end $command\n

              $but config -text Stop -command Stop

      }

}

 


# Read and log output from the program

proc Log {} {

      global input log

      if [eof $input] {

              Stop

      } else {

              gets $input line

              $log insert end $line\n

              $log see end

      }

}

 


# Stop the program and fix up the button

proc Stop {} {

      global input but

      catch {close $input}

      $but config -text "Run it" -command Run

}

 


○ 첫 번째 명령은 윈도우 관리자에 의해 구현되는 윈도우의 타이틀 바를 바꾼다.

wm title .ExecLog

○ wm 명령은 윈도우 관리자와 통신을 한다.

○ 윈도우 관리자는 윈도우를 열고 닫으며 크기를 바꿀 수 있게 해 주는 프로그램이다.

○ 사용자 인터페이스의 최상위 부분에 나타날 widget들을 담기 위해 프레임이 생성된다.

○ 프레임은 widget을 위한 공간을 마련하기 위해 border를 가지고 있다.

frame .top -borderwidth 10

○ 프레임은 메인 윈도우 안에 위치된다.

○ 기본적인 packing 면은 top이므로 -side top 옵션은 빼도 상관없다.

○ -fill x 옵션은 메인 윈도우의 크기만큼 프레임이 커지도록 한다.

○ 여기서는 두 개의 버튼이 생성된다.

○ 하나의 버튼은 프로그램을 수행하는 데 사용되고 또 하나의 버튼은 ExecLog 프로그램을 종료하는 데 사용된다.

○ 각 버튼의 이름은 .top.qui과 .top.run이다.

○ label과 entry도 .top 프레임의 자식으로 생성된다.

○ entry의 크기는 입력받을 수 있는 문자 개수로 정해진다.

○ relief 속성은 화면에 어떻게 보일 것인지를 정한다.

○ label과 entrysms .top 프레임의 왼쪽에 배치된다.

○ entry widget에 대해 지정된 키 바인딩은 Enter 키나 Ctrl-C 키를 눌렀을 때에도 어떤 동작을 취할 수 있게 해줌.○ bind 명령은 Tcl 명령을 어떤 widget의 X event와 연결시킨다.

○ <Return> 이벤트는 사용자가 Enter 키를 눌렀을 때 발생된다.

○ <Control-c> 이벤트는 사용자가 Ctrl-C 키를 눌렀을 때 발생된다.

○ 이벤트가 entry widget으로 가기 위해서는 입력 포커스가 widget에 가 있어야 하므로 focus 명령으로 입력 포커스를 entry widget에 보내 준다.

○ text widget이 생성되고 프레임에 스크롤바와 함께 들어가게 된다.

○ scrollbar은 Tk에서 별도의 widget이며 여기서 사용한 방법과 같이 다른 widget과 연결된다.

○ text widget의 yscrollcommand 옵션은 widget이 수정될 때 scrollbar의 화면 표시를 갱신하게 된다.

○ setgrid 속성을 켜면 메인 윈도우의 크기를 바꿀 수 있게 된다.

○ Run 프로시져와 Log 프로시져, Stop 프로시져는 프로그램을 수행하고 결과를 기록하며 수행을 중지시키는 일을 하는 프로시져이다.

 


10.2.  Tcl Shell

○ 다음은 Tcl Shell 프로그램을 구현해 본 것이다.

#!/usr/local/bin/wish

# Simple evaluator. It executes Tcl in its own interpreter

# and it uses up the following identifiers

# Tk widgets:

#   .eval - the frame around the text log

# Procedures:

#   _Eval - the main eval procedure

# Variables:

#   prompt - the command line prompt

#   _t - holds the ID of the text widget

 


# A frame, scrollbar, and text

frame .eval

set _t [text .eval.t -width 80 -height 20 \

      -yscrollcommand {.eval.s set}]

scrollbar .eval.s -command {.eval.t yview}

pack .eval.s -side left -fill y

pack .eval.t -side right -fill both -expand true

pack .eval -fill both -expand true

 


# Insert the prompt and initialize the limit mark

.eval.t insert insert "Tcl eval log\n"

set prompt "tcl> "

.eval.t insert insert $prompt

.eval.t mark set limit insert

.eval.t mark gravity limit left

focus .eval.t

 


# Key bindings that limit input and eval things

bind .eval.t <Return> { _Eval .eval.t ; break }

bind .eval.t <Any-Key> {

      if [%W compare insert < limit] {

              %W mark set insert end

      }

}

bindtags .eval.t {.eval.t Text all}

 


proc _Eval { t } {

      global prompt _debug

      set command [$t get limit end]

      if [info complete $command] {

              set err [catch {uplevel #0 $command} result]

              $t insert insert \n$result\n

              $t insert insert $prompt

              $t see insert

              $t mark set limit insert

              return

      }

}

○ 위의 프로그램을 실행시키면 그림 10-3과 같은 화면이 나타난다.

 

그림 10-3). Tcl Shell 프로그램의 실행예



11.  Pack 형상 관리자

○ 형상 관리자는 화면에 widget을 배치한다.

○ 형상 관리자에는 여러 가지 종류가 있으며 각 widget마다 다른 종류의 형상 관리자를 사용할 수 있다.

○ 여기서는 주로 pack 형상 관리자에 대해 알아 보도록 한다.

○ 형상 관리자는 부모 widget을 하나 사용하며 그 안에 여러 개의 자식 widget을 배치하게 된다.

○ 부모 widget은 보통 프레임이지만 반드시 그렇지는 않다.

○ 하나의 widget 한번에 하나의 형상 관리자에 의해서만 관리된다.

○ widget이 형상 관리자와 연결되지 않으며 화면에 나타나지 않는다.

○ packer는 강력한 형상 관리자이다.

○ 각 윈도우의 정확한 위치를 상세히 설명하는 대신, 윈도우가 어떤 방식으로 배치되어야 하는지만 알려 주면 packer가 알아서 위치를 찾아 배치하게 된다.

○ 화면에 자신이 원하는 대로 widget들을 배치하기 위해서는 packer가 사용하는 알고리즘을 잘 이해해야만 한다.

○ 본 절에서는 예제를 통해 packer 형상 관리자에 대해 살펴 본다.

○ 본 절에서 소개하는 예제에서 메인 윈도우의 배경은 항상 검은 색이다.

 


11.1.  모서리쪽에 붙이기

○ 다음 예제에서는 두 개의 프레임을 생성한 후 각각을 메인 윈도우의 위쪽에 붙인다.

○ 둘 중 더 위쪽에 배치될 윈도우가 .one이며 그 아래에 .two 윈도우가 배치된다.

○ 모서리 위치는 top, right, bottom, left 중 하나로 지정할 수 있다.

# Make the main window black

. config -bg black

# Create and pack two frames

frame .one -width 40 -height 40 -bg white

frame .two -width 100 -height 50 -bg grey50

pack .one .two -side top

○ 위의 예제를 실행하면 다음과 같은 화면이 만들어진다.

 

그림 10-4). 모서리에 붙이기

 


○ 위의 예제에서 메인 윈도우는 두 개의 자식 윈도우를 담을 만큼의 크기로 줄어들었다.

○ 이러한 기능을 없애려면 pack propagate 명령을 사용한다.

○ pack propagate 명령을 부모 프레임에 사용하면 부모 윈도우는 자식 윈도우의 크기에 맞추어 크기가 변경되지 않는다.

# Make the main window black

. config -bg black

# Create and pack two frames

frame .one -width 40 -height 40 -bg white

frame .two -width 100 -height 50 -bg grey50

pack propagate . false

pack .one .two -side top

○ 위의 예제를 실행하면 그림 10-5와 같은 화면이 만들어진다.

 

그림 10-5). pack propagate 명령의 사용예

 

 

11.2.  가로 세로 쌓기

○ 일반적으로 프레임 안에서는 가로나 세로로 widget을 쌓을 수 있다.

○ 만약 한 프레임 안의 자식 widget들에 대해 left와 top을 동시에 사용한다면 그 결과는 원하는 것과 다를 수 있다.

○ 이러한 경우는 서로 다르게 쌓고 싶은 widget들을 담을 자식 프레임을 만드는 것이 좋다.

○ 예를 들어 앞의 예제에서 위쪽 프레임에 버튼을 가로로 나열해 보자.

# Make the main window black

. config -bg black

# Create two frames

frame .one -bg white

frame .two -width 100 -height 50 -bg grey50

# Create a row of buttons

foreach b {alpha beta gamma} {

      button .one.$b -text $b

      pack .one.$b -side left

}

pack .one .two -side top

○ 위의 예제를 실행시키면 그림 10-6과 같은 화면이 나타난다.

 

그림 10-6). 버튼을 가로로 나열한 예


○ 이번에는 좀더 복잡한 배치를 위해 프레임을 중복해서 사용하도록 하자.

# Make the main window black

. config -bg black

# Create two frames

frame .one -bg white

frame .two -width 100 -height 50 -bg grey50

# Create a row of buttons

foreach b {alpha beta} {

      button .one.$b -text $b

      pack .one.$b -side left

}                

# Create a frame for two more buttons

frame .one.right

foreach b {delta epsilon} {

      button .one.right.$b -text $b

      pack .one.right.$b -side bottom

}

pack .one.right -side right

pack .one .two -side top

○ 위의 예제를 실행시키면 그림 10-7과 같은 화면이 나온다.

 

그림 10-7). 프레임을 중복사용한 예

 

 

11.3.  Cavity 모델

○ packing 알고리즘은 프레임 안의 남는 공간에 대해 cavity 모델을 사용한다.

○ 메인 윈도우가 생성될 때 메인 프레임은 비어 있으며 widget을 배치할 자리가 마련되어 있다.

○ widget은 남은 공간의 한 면을 전부 차지한다.

○ 이러한 규칙을 설명하기 위해 다음 예제를 살펴 보자.

# Make the main window black

. config -bg black

# pack two frames on the bottom.

frame .one -width 100 -height 50 -bg grey50

frame .two -width 40 -height 40 -bg white

pack .one .two -side bottom

# pack another frame to the right

frame .three -width 20 -height 20 -bg grey75

pack .three -side right

○ 위의 예제를 실행시키면 그림 10-8과 같은 화면이 나온다.

 

그림 10-8). Cavity 모델


○ 위의 예제에서 .three widget을 오른쪽에 배치하였으나 .two의 아래로는 내려가지 않았다.

○ 그것은 .two widget이 bottom 면에 배치되어 있으므로 가로쪽으로 한 면을 전부 차지하고 있기 때문이다.

 


11.4.  팩킹 공간과 디스플레이 공간

○ packer는 팩킹 공간과 디스플레이 공간을 구분한다.

○ 디스플레이 공간은 widget을 화면에 보여주기 위해 요청되는 구역이다.

○ 팩킹 공간은 widget의 배치를 위해 허용하는 구역이다.

○ 화면 구성상의 특징 때문에 팩킹 공간은 디스플레이 공간보다 더 클 수 있다.

○ -fill 옵션은 디스플레이 공간이 차지하는 공간을 다 채우도록 만든다.

# Make the main window black

. config -bg black

# pack two frames on the bottom.

frame .one -width 100 -height 50 -bg grey50

frame .two -width 40 -height 40 -bg white

# pack with fill enabled

pack .one .two -side bottom -fill x

frame .three -width 20 -height 20 -bg red

pack .three -side right -fill x

○ 위의 예제를 실행시키면 그림 10-9와 같은 화면이 나온다.

 

그림 10-9). fill 옵션의 사용예


○ -fill x 옵션이 사용되면 위와 같이 자신이 차지하는 구역 전부에 꽉 채워져 화면에 나타나게 된다.

○ 이와 같은 fill 옵션은 다음과 같이 메뉴바를 만드는 데 많이 사용된다.

frame .menubar -bg white

frame .body -width 150 -height 50 -bg grey50

# Create buttons at either end of the menubar

foreach b {alpha beta} {

      button .menubar.$b -text $b

}

pack .menubar.alpha -side left

pack .menubar.beta -side right

# Let the menu bar fill along the top

pack .menubar -side top -fill x

pack .body

○ 위의 예제를 실행시키면 그림 10-10과 같은 화면이 나타난다.

 

그림 10-10). 메뉴바에서의 fill 옵션 사용예


○ 좀더 많은 공간을 확보하고 싶을 때에는 x나 y 방향으로 더 많은 공간을 요구하는 -ipadx나 -ipady 옵션을 사용한다.

○ 다음 예제는 위의 예제에 내부 패딩을 추가하였다.

# Create and pack two frames

frame .menubar -bg white

frame .body -width 150 -height 50 -bg grey50

# Create buttons at either end of the menubar

foreach b {alpha beta} {

      button .menubar.$b -text $b

}

pack .menubar.alpha -side left -ipady 10

pack .menubar.beta -side right -ipadx 10

# Let the menu bar fill along the top

pack .menubar -side top -fill x -ipady 5

pack .body

○ 위의 예제를 실행시키면 그림 10-11과 같은 화면이 나타난다.

 

그림 10-11). 내부 패딩을 추가한 예


○ 내부 패딩의 크기를 다르게 했으므로 alpha와 beta 버튼의 크기는 다르다.

○ 버튼은 -padx와 -pady의 또다른 패딩 옵션을 제공한다.

○ -padx와 -pady 옵션은 버튼 안에 들어 가는 글자가 버튼의 경계보다 안 쪽에 들어가게 한다.

# Foo has internal padding from the packer

button .foo -text Foo -anchor e -padx 0 -pady 0

pack .foo -side right -ipadx 10 -ipady 10

# Bar has its own padding

button .bar -text Bar -anchor e -pady 10 -padx 10

pack .bar -side right -ipadx 0 -ipady 0

○ 위의 예제를 실행시키면 그림 10-12와 같은 화면이 나타난다.

 

그림 10-12). 버튼의 패딩옵션 사용예


○ 원래 -padx와 -pady 옵션은 외부 패딩을 정하기 위해 사용된다.

○ 이것은 widget의 바깥 부분에 들어가는 패딩이며 3차원 효과를 나타내는 부분이기도 하다.

. config -borderwidth 10

# OK is the default button

frame .ok -borderwidth 2 -relief sunken

button .ok.b -text OK

pack .ok.b -padx 5 -pady 5

# Cancel is not

button .cancel -text Cancel

pack .ok .cancel -side left -padx 5 -pady 5

○ 위의 예제를 실행시키면 그림 10-13과 같은 화면이 나타난다.

 

그림 10-13). 외부 패딩의 사용 예

 

 

11.5.  크기 확장과 크기 조절

○ -expand true 옵션은 widget이 자기 자리가 아니지만 비어 있는 곳까지 확장하도록 해 준다.

○ -expand 옵션이 사용되는 더 일반적인 예는 크기를 변경할 수 있는 윈도우에서이다.

○ 윈도우가 더 커지면 새로 만들어진 남는 공간을 사용하라고 widget들에게 말해 주어야 한다.

○ 윈도우의 크기는 사용자가 직접 변경할 수도 있고 프로그램상에서 wm geometry 명령을 사용해 바꿀 수도 있다.

○ 기본적으로 윈도우의 크기는 변경할 수 없게 되어 있다.

○ wm minisize나 wm maxsize 명령은 윈도우의 크기를 바꿀 수 있게 하는 부가적인 효과를 가지고 있다.

# Make the main window black

. config -bg black

# Create and pack two frames

frame .menubar -bg white

frame .body -width 150 -height 50 -bg grey50

# Create buttons at either end of the menubar

foreach b {alpha beta} {

      button .menubar.$b -text $b

}

pack .menubar.alpha -side left

pack .menubar.beta -side right

# Let the menu bar fill along the top

pack .menubar -side top -fill x

pack .body

# Resize the main window to be bigger

wm geometry . 200x100

# Allow interactive resizing

wm minsize . 100 50

○ 위의 예제를 실행시키면 그림 10-14와 같은 화면이 나온다.

 

그림 10-14). interactive resizing이 허용된 윈도우의 예


○ 위의 예제 실행 후에 다음 명령을 실행하면 윈도우는 그림 10-15와 같이 바뀐다.

pack .body -expand true -fill both

 

그림 10-15). expand 사용 예


○ 그러나 하나의 부모 widget 밑에 있는 두 개 이상의 widget이 모두 -expand 옵션을 사용하는 경우는 각 widget이 비례적으로 남은 공간을 나누어 가지게 된다.

○ 위의 pack 명령 대신 다음 명령을 실행하면 그림 10-16과 같이 화면이 바뀐다.

pack .menubar -expand true -fill x

pack .body -expand true -fill both

 

그림 10-16). fill 옵션의 사용예

 

 

11.6.  Anchoring

○ widget이 디스플레이 공간보다 더 많은 팩킹 공간이 있을 때에는 -anchor 옵션을 사용해 팩킹 공간 상에서의 위치를 지정할 수 있다.

○ 기본 위치는 center이다.

○ 가능한 위치는 n, ne, e, se, s, sw, w, nw이다.

# Make the main window black

. config -bg black

# Create two frames to hold open the cavity

frame .prop -bg white -height 80 -width 20

frame .base -width 120 -height 20 -bg grey50

pack .base -side bottom

# Float a label and the prop in the cavity

label .foo -text Foo

pack .prop .foo -side right -expand true

○ 위의 예제를 실행시키면 그림 10-17과 같은 화면이 나타난다.

 

그림 10-17). widget의 기본 위치


○ .base 프레임은 바닥에 배치된다.

○ .prob와 .foo 레이블은 오른쪽에 배치되지만 fill 옵션은 선택되지 않는다.

○ 그에 따라 .foo는 기본적으로 중앙에 배치되게 된다.

○ 다음 예는 -anchor 옵션을 사용하는 예이다.

# Make the main window black

. config -bg black

# Create two frames to hold open the cavity

frame .prop -bg white -height 80 -width 20

frame .base -width 120 -height 20 -bg grey50

pack .base -side bottom

# Float a label and the prop

# Change their position with anchors

label .foo -text Foo

pack .prop .foo -side right -expand true -anchor sw

pack .foo -side right -expand true -anchor ne

○ 위의 예제를 실행시키면 그림 10-18과 같은 화면이 나타난다.

 

그림 10-18). anchor 옵션의 사용예

 

 

11.7.  팩킹 순서

○ packer는 프레임에 들어가는 자식 widget들의 순서를 유지하고 있다.

○ 기본적으로 새로 추가된 widget은 가장 마지막 팩킹 순서 뒤에 추가되게 된다.

○ 팩킹 순서의 가장 큰 효과는 가장 높은 팩킹 순서를 가지는 widget이 가장 모서리쪽에 가깝게 배치된다는 것이다.

○ -before나 -after 팩킹 옵션을 사용하면 팩킹 순서를 바꿀 수 있다.

○ 이미 들어간 widget의 팩킹 순서도 바꿀 수 있다.

# Create five labels in order

foreach label {one two three four five} {

      label .$label -text $label

      pack .$label -side left -padx 5

}

# ShuffleUp moves a widget to the beginning of the order

proc ShuffleUp { parent child } {

      set first [lindex [pack slaves $parent] 0]

      pack $child -in $parent -before $first

}

# ShuffleDown moves a widget to the end of the order

proc ShuffleDown { parent child } {

      pack $child -in $parent

}

○ 위의 예제를 실행시키면 그림 10-19와 같은 화면이 나타난다.

 

그림 10-19). 기본 팩킹


○ 여기서 다음 두 명령을 실행시키면 화면이 그림과 같이 바뀐다.

ShuffleUp . .five

ShuffleDown . .three

 

그림 10-20). 팩킹 순서를 바꾼 예


○ pack slaves 명령은 팩킹 순서로 자식 widget의 리스트를 돌려 준다.

○ 위의 예제의 ShuffleUp 명령은 이 pack slaves 명령을 사용한다.

○ 지금까지의 모든 예제에서는 widget이 부모 frame에 들어갔다.

○ 일반적으로 모든 widget은 그 부모의 자손 window에는 어디에나 포함될 수 있다.

○ 예를 들어 .a.b widget은 .a, .a.c, .a.d.e.f 등의 window에 모두 포함될 수 있다.

○ -in 옵션은 다른 부모를 선택하게 하여 준다.

○ pack forget 명령은 포함된 widget을 끄집어 낸다.

 

 

12.  X 이벤트와 Tcl 명령의 연결

○ 바인딩은 Tcl 명령을 X 윈도우 시스템의 이벤트와 연결시키는 작업을 말한다.

○ 이벤트에는 다음과 같은 경우에 발생한다.

- 키가 눌려진 경우

- 키에서 손을 뗀 경우

- 마우스 버튼이 눌려진 경우

- 마우스 버튼을 놓은 경우

- 윈도우 안으로 마우스 포인터가 들어가는 경우

- 마우스 포인터가 윈도우 밖으로 빠져 나가는 경우

- 윈도우의 크기가 변경되는 경우

- 윈도우가 열리는 경우

- 윈도우가 닫히는 경우

- 입력 포커스를 얻은 경우

- widget이 없어지는 경우

○ 바인딩은 binding tag들로 정의되며 각 widget은 binding tag들의 집합과 연결된다.

○ 바인딩과 widget이 분리됨으로써 유연하고 강력한 시스템을 구성할 수 있다.

 


12.1.  bind 명령

○ bind 명령은 현재 바인딩에 대한 정보를 돌려 주고 새로운 바인딩을 정의하는 데 사용된다.

○ bind 명령의 문법은 다음과 같다.

bind bindingTag ?eventSequence? ?command?

○ bindingTag는 주로 widget 클래스 이름이거나 widget 인스턴스 이름이다.

○ binding tag는 뒤에서 자세히 설명한다.

○ 하나의 파라미터만 주는 경우 명령 바인딩이 설정된 이벤트들을 돌려 준다.

bind Menubutton

=> <Key-space> <ButtonRelease-1> <B1-Motion> <Motion> <Button-1> <Leave> <Enter>

○ <Button-1>은 왼쪽 마우스 버튼을 클릭하는 경우 발생하는 이벤트이다.

○ <B1-Motion>은 왼쪽 마우스 버튼을 클릭한 채로 마우스를 움직이는 경우 발생하는 이벤트이다.

○ 명령어의 바인딩은 이와 같은 이벤트의 나열에 대해 정의된다.

○ bind 명령에 eventSequence 파라미터를 주면 그 이벤트에 연결된 명령을 보여 준다.

○ 이벤트 바인딩을 위해 사용되는 Tcl 명령은 이벤트 키워드를 위한 몇 가지 추가적인 문법을 제공한다.

○ 이러한 키워드는 '%' 기호로 시작한다.

○ 이러한 키워드들은 이벤트와 관련된 데이터로 대체.

○ %W는 widget의 경로명으로 대치된다.

○ %X와 %Y 키워드는 이벤트 발생 좌표로 대치된다.

○ %는 인용 부호에 상관없이 항상 치환된다.

○ % 기호를 사용하기 위해서는 %%로 사용.

○ 이러한 이유로 바인딩 명령은 프로시져를 호출하는 방법으로 짧게 만드는 것이 좋다.

○ 새로운 바인딩은 연속된 일련의 이벤트와 명령을 줌으로써 정의된다.

bind Menubutton <B1-Motion> {tkMbMotion %W down %X %Y}

○ 바인딩 명령의 처음이 '+' 기호로 시작하면 그 명령은 바인딩 명령에 추가된다.

bind bindingTag event {+ command args}

○ 이벤트에 대한 바인딩을 삭제하기 위해서는 이벤트를 빈 스트링과 연결시킨다.

bind bindingTag event { }

○ 바인드 명령은 실행 전체에 걸쳐 영향을 미친다.

 


12.2.  bindtags 명령

○ 바인딩은 관련 바인딩을 묶는 binding tag와 연결.

○ 각 widget은 binding tag의 집합과 연결되어 있다.

○ bindtags 명령은 widget의 binding tag를 제어한다.

○ bindtags 명령의 문법은 다음과 같다.

bindtags widget ?tagList?

○ 다음 명령은 text widget에 대한 기본 binding tag를 돌려 준다.

bindtags .t     =>    .t Text . all

○ 모든 Tk widget은 기본적으로 다음과 같은 4개의 binding tag를 가지고 있다.

- widget의 Tk 경로명

- widget의 클래스. 클래스 이름은 그 widget을 생성하는 명령으로부터 도출해 낼 수 있다. 예를 들어 버튼 widget의 클래스 이름은 Button이고 캔버스의 클래스 이름은 Canvas이다.

- widget의 맨 꼭대기 윈도우의 Tk 경로명

- 전체 binding tag인 'all'

○ bindtags 명령을 사용하면 binding tag와 그 순서를 바꿀 수 있다.

○ tagList 파라미터는 Tcl 리스트이다.

○ 다음 명령은 $t에 대한 binding tag를 재배치하고 . binding tag를 삭제한다.

bindtags $t [list all Text $t]

○ tag 리스트의 순서는 이벤트가 집합의 둘 이상의 binding tag와 일치되는 경우에 수행할 명령의 순서를 결정한다.

○ Tk widget은 자신이 속한 클래스에 바인딩하는 것을 기본 동작으로 한다.

○ widget의 이름에 이벤트를 바인딩해서 추가적인 바인딩을 추가할 수 있다.

○ 가장 꼭대기의 윈도우에 대한 바인딩은 대화 상자에서 단축키를 처리하기 위해 사용할 수 있다.

○ all binding tag : 全 widget에 해당하는 바인딩을 의미.

○ all에 정의된 기본 바인딩은 widget 간에 입력 포커스를 변경하는 것이다.

frame .one -width 30 -height 30

frame .two -width 30 -height 30

bind Frame <Enter> {%W config -bg red}

bind Frame <Leave> {%W config -bg white}

bind .two <Any-Button> {puts "Button %b at %x %y"}

pack .one .two -side left

bind all <Control-c> {destroy %W}

bind all <Enter> {focus %W}

○ 위의 예제에서 Frame 클래스는 마우스가 들어오면 빨간색으로 변하고 나가면 하얀색으로 변하는 명령과 바인딩되었다.

○ .two widget은 마우스 버튼이 눌려진 경우 그 정보를 화면에 보여주게 하였다.

○ all에 대해 Control-c에 대한 바인딩을 정의하였으므로 모든 widget은 Ctrl-C 키를 누른 경우 사라지게 된다.

 


12.3.  이벤트 표기법

○ 이벤트는 다음과 같은 표기법에 의해 표현된다.

<modifier-modifir-type-detail>

○ 여기서 가장 중요한 부분은 Button이나 Motion 등의 단어가 사용되는 type 부분이다.

○ detail은 키 이름이나 버튼 종류를 지정하기 위해 사용한다. (예를 들어 Key-a, Button-1과 같이)

○ modifier는 이벤트가 발생할 때 이미 눌려져 있는 키를 의미한다.(Control-Key-a 또는 B2-Motion등과 같이)

○ < >로 둘러 싸서 하나의 이벤트임을 나타낸다

○ 다음은 모든 이벤트 type을 나타내고 있다.

- ButtonPress, Button: 마우스 버튼이 눌려졌다.

- ButtonRelease: 마우스 버튼이 떼어졌다.

- Circulate: 윈도우의 쌓이는 순서가 바뀌었다.

- Configure: 윈도우의 크기, 위치, border 또는 쌓이는 순서가 바뀌었다.

- Destroy: 윈도우가 사라졌다.

- Enter: 마우스가 윈도우 안으로 들어왔다.

- Expose: 윈도우가 아이콘 표시에서 원래 화면으로 바뀌었다.

- FocusIn: 윈도우가 입력 포커스를 받았다.

- FocusOut: 윈도우가 입력 포커스를 잃었다.

- Gravity: 부모 윈도우의 크기가 바뀌어 윈도우가 이동되었다.

- KeyPress, Key: 키가 눌려졌다.

- KeyReleas: 키가 떼어졌다.

- Motion: 마우스가 윈도우상에서 움직이고 있다.

- Leave: 마우스가 윈도우를 떠나고 있다.

- Map: 윈도우가 열려졌다.

- Property: 윈도우의 속성이 변경되거나 삭제되었다.

- Reparent: 윈도우가 reparent 되었다.

- Unmap: 윈도우가 아이콘 표시로 바뀌었다.

- Visibility: 윈도우의 보이는 모양이 바뀌었다.

 


12.4.  키보드 이벤트

○ KeyPress 이벤트와 KeyRelease 이벤트는 서로 다른 명령을 수행하게 할 수 있게 하기 위해 구분되어 있다.

○ KeyPress는 줄여서 Key라고 써도 되며 아예 Key도 생략할 수 있다.

○ KeyPress의 경우는 양쪽을 둘러싸는 < > 기호를 생략할 수 있다.

○ 다음은 모두 같은 의미이다.

- <KeyPress-a>

- <Key-a>

- <a>

- a

○ 이 외에도 다음과 같은 특수 키들이 정의되어 있다.

- Return

- Escape

- BackSpace

- Tab

- Up

- Down

- Left

- Right

- comma

- period

- dollar

- asciicircum

- numbersign

- exclam

 


12.5.  마우스 이벤트

○ 버튼 이벤트의 경우도 ButtonPress 이벤트와 ButtonRelease 이벤트가 분리되어 있다.

○ 다음은 모두 같은 의미이다.

- <ButtonPress-1>

- <Button-1>

- <1>

○ 숫자키 1이 눌린 이벤트인 경우는 <1>이라고 표기하면 안되고 <KeyPress-1>, <Key-1> 또는 그냥 1이라고 표기하여야 한다.

○ 마우스의 좌표는 %x와 %y 키워드로 얻음.

○ 이렇게 얻은 마우스좌표는 widget에서의 상대 좌표.

○ %X와 %Y는 화면상에서의 절대 좌표를 돌려 준다.

 


12.6.  지정자(modifier)

○ 지정자는 이벤트가 발생한 시점에 다른 키나 버튼이 눌려진 상태임을 나타낸다.

○ 전형적인 지정자로 Shift와 Control 키를 들수있다.

○ 예를 들어 Shift와 Control 키를 동시에 누르고 c 키를 눌렀을 때 발생하는 이벤트는 <Shift-Control-Key-c>로 표시할 수 있다.

○ 다음은 주로 사용되는 지정자들이다.

- Control: Control 키

- Shift: Shift 키

- Lock: caps-lock 키

- Meta: 메타 키

- Alt: Alt 키

- Button1(B1), Button2(B2), ... Button5(B5): 1(2,3...5)번째 마우스 버튼

- Double: 더블 클릭

- Triple: 세 번 연속으로 클릭

- Any: 지정자의 어떤 조합도 허용

 


12.7.  이벤트의 나열

○ bind 명령은 연속적으로 발생하는 둘 이상의 이벤트에 대해서도 명령을 지정할 수 있는 기능을 제공.

bind . a {puts stdout A}

bind . abc {puts stdout C}

bind .foo <Control-x><Control-s> {Save; break}

 


12.8.  이벤트 키워드

○ 다음은 바인딩에서 사용할 수 있는 키워드들이다.

- %%: % 기호

- %#: 이벤트의 일련 번호

- %a: 이벤트의 above 필드

- %b: 버튼 번호

- %c: count 필드

- %d: detail 필드

- %f: 포커스 필드

- %h: height 필드

- %k: keycode 필드

- %m: mode 필드

- %o: override_redirect 필드

- %p: place 필드

- %s: state 필드

- %t: time 필드

- %v: value_mask 필드

- %w: width 필드

- %x: x 상대 좌표

- %y: y 상대 좌표

- %A: 출력되는 문자

- %B: border 필드

- %E: send_event 필드

- %K: 이벤트의 keysim

- %N: 10진수로 표현된 keysim

- %R: 루트 윈도우 ID

- %S: sub 윈도우 ID

- %T: type 필드

- %W: widget의 경로명

- %X: x_root 필드

- %Y: y_root 필드

 

 

▶ 출처:  홍익대학교


▶ 원문: http://www.cs.hongik.ac.kr/~kimyj/research/gaia/tcltk.hwp


◆ 가우리정보센터 (GBC)

반응형

'서버관련지식' 카테고리의 다른 글

TCL/TK 문법 (1)  (0) 2007.04.29
Posted by Real_G