grab — 포인터·키보드 이벤트를 창 하위 트리로 가두기
grab — 포인터·키보드 이벤트를 창 하위 트리로 가두기
모달 대화상자처럼, 특정 창이 떠 있는 동안 다른 창이 조작되지 않도록 막아야 할 때가 있어요. Tk의 grab 명령은 포인터와 키보드 이벤트를 특정 창과 그 자손들로만 가두는 간단한 장치를 구현합니다.
본문
개요
grab ?-global? window
grab option ?arg arg ...?
동작 방식
이 명령은 Tk용 포인터 및 키보드 grab을 구현해요. Tk의 grab은 Xlib 문서에 설명된 grab과는 다릅니다.
특정 창에 grab이 설정되면 Tk는 모든 포인터 이벤트를 grab 창과 Tk 창 계층에서 그 자손들로 제한해요. 포인터가 grab 창의 하위 트리 안에 있으면 grab이 전혀 없을 때와 똑같이 동작하고 모든 이벤트가 정상적으로 보고됩니다. 포인터가 window의 트리 밖에 있으면 버튼 누름·놓음과 마우스 이동 이벤트가 window에 보고되고, 창 진입·퇴출 이벤트는 무시돼요. grab 하위 트리가 포인터를 "소유"하므로 grab 하위 트리 밖의 창은 화면에 보이지만 grab이 풀릴 때까지 반응하지 않습니다. grab 창 아래의 창 트리는 toplevel 창을 포함할 수 있고, 그 경우 그 toplevel 창들과 자손들은 grab 중에도 마우스 이벤트를 계속 받아요.
두 가지 grab 형태가 가능합니다: 로컬(local)과 글로벌(global). 로컬 grab은 grab을 건 응용에만 영향을 줍니다. 다른 응용에는 grab이 없었다는 것처럼 이벤트가 보고돼요. grab은 기본적으로 로컬입니다. 글로벌 grab은 화면의 모든 응용을 잠가서, grab을 건 응용의 주어진 하위 트리만 포인터 이벤트(마우스 버튼 누름, 버튼 놓음, 포인터 이동, 창 진입, 창 퇴출)에 반응하게 해요. 글로벌 grab 중에는 창 관리자도 포인터 이벤트를 받지 못합니다.
로컬 grab 중에는 키보드 이벤트(키 누름·놓음)가 평소대로 전달됩니다. 창 관리자가 어떤 응용이 키보드 이벤트를 받을지 제어하고, grab을 건 응용의 어떤 창으로 보내진다면 포커스 창으로 리다이렉트돼요. 글로벌 grab 중에는 Tk가 키보드를 잡아 모든 키보드 이벤트가 항상 grab을 건 응용으로 보내집니다. 응용 안에서 어떤 창이 키보드 이벤트를 받을지는 여전히 focus 명령으로 정합니다. 키보드 grab은 grab이 풀릴 때 함께 풀려요.
macOS에서 글로벌 grab은 한 Tk 프로세스가 만든 모든 창에 영향을 줍니다. 그 프로세스에서 grab 창 외의 어떤 창도 포커스를 받을 수 없어서, 다른 창은 키나 마우스 이벤트를 받지 못해요. macOS에서 로컬 grab은 한 Tcl 인터프리터가 만든 모든 창에 영향을 줍니다. 로컬 grab 중에는 Tk 프로세스에 속한 어떤 창이든 포커스할 수 있지만, grab 창이 그 인터프리터가 만든 창 중 키·마우스 이벤트를 받는 유일한 창이에요. 같은 프로세스에 속하지만 다른 인터프리터가 만든 창은 키·마우스 이벤트를 정상적으로 계속 받습니다.
grab은 특정 디스플레이에 적용됩니다. 응용이 여러 디스플레이에 창을 갖고 있다면 각 디스플레이에 별도의 grab을 설정할 수 있어요. 특정 디스플레이의 grab은 그 디스플레이의 창에만 영향을 줍니다. 한 디스플레이에서 서로 다른 응용이 동시에 로컬 grab을 가질 수 있지만, 주어진 디스플레이에서 글로벌 grab을 가질 수 있는 응용은 한 번에 하나뿐입니다.
grab 명령은 다음 형태 중 하나를 가질 수 있어요.
grab ?-global? window — 아래 설명하는 grab set과 같습니다.
grab current ?window? — window를 지정하면 이 응용에서 window의 디스플레이에 대한 현재 grab 창의 이름을 돌려줍니다. 그런 창이 없으면 빈 문자열을 돌려줘요. window를 생략하면 명령은 이 응용이 모든 디스플레이에 대해 grab한 모든 창을 요소로 하는 리스트를 돌려주고, grab이 없으면 빈 문자열을 돌려줍니다.
grab release window — window에 grab이 있으면 풀고, 없으면 아무것도 하지 않아요. 빈 문자열을 돌려줍니다.
grab set ?-global? window — window에 grab을 설정합니다. -global을 지정하면 글로벌 grab, 아니면 로컬 grab이에요. window의 디스플레이에 대해 이 응용이 이미 grab을 적용 중이었다면 자동으로 풀립니다. window에 이미 grab이 있고 요청한 grab과 같은 글로벌/로컬 형태라면 명령은 아무것도 하지 않아요. 빈 문자열을 돌려줍니다.
grab status window — window에 현재 grab이 없으면 none, 로컬 grab이 설정돼 있으면 local, 글로벌 grab이 설정돼 있으면 global을 돌려줍니다.
주의 (WARNING)
글로벌 grab으로 디스플레이를 완전히 사용 불가능하게 만들기는 아주 쉽습니다(예: 이벤트에 반응하지 않는 위젯에 grab을 걸고 grab을 풀 메커니즘을 제공하지 않는 경우). 사용할 때 극도로 조심하세요!
버그 (BUGS)
위에서 설명한 단순한 grab 효과를 만들기 위해 엄청나게 복잡하고 지저분한 구현이 필요했어요. 현재 구현에서 응용이 Tk grab 절차를 통하지 않고 Xlib grab 기능을 사용하는 것은 안전하지 않습니다. 응용이 X의 grab 메커니즘을 직접 조작하려 하면 아마 깨질 거예요.
한 프로세스가 여러 Tk 응용을 관리한다면, 주어진 디스플레이에서 그중 하나만 특정 시점에 로컬 grab을 가질 수 있어요. 응용들이 다른 프로세스에 있다면 이 제한은 없습니다.
예제
버튼 그룹에서 하나의 버튼만 클릭할 수 있도록 grab을 설정합니다. 다른 버튼들은 가운데 버튼이 클릭될 때까지 마우스에 반응하지 않아요.
pack [button .b1 -text "Click me! #1" -command {destroy .b1}]
pack [button .b2 -text "Click me! #2" -command {destroy .b2}]
pack [button .b3 -text "Click me! #3" -command {destroy .b3}]
grab .b2
더 알아보기
- busy — 응용이 busy 상태일 때 마우스·키보드 입력 차단