Firemonkey에서의 Z-Order와 BringToFront, SendToBack
Firemonkey에서의 C++ Builder로 Layout을 만들다 보면 BringToFront, SendToBack 등을 자주 사용하게 된다. 문제는 이것이 계층을 구분하기 때문에 우선순위등이 존재한다는 것이다. 솔직히 이것에 대해서 설명해 주는 사람이나 책자들이 없어서 몰랐는데 이번에 영역 외 터치 동작을 구현하기 위해서 뻘짓을 하다 알게 되었다.
험프리님의 예제를 보고 이런식으로 적용해야지 했는데 되질 않아서 고생을 좀 했다.
보던 예제는 "[모바일앱예제] 사이드바 형태 메뉴(Sidebar drawer menu) 만들기" 이고, 역시 델파이로 되어 있다. 문제는 이대로 따라 하면 안된다는 것이다. 여기서 lytSidebarHelper라는 Layout이 있는데, 이거 Layout이 아니라 TRectangle 같다. 여기에 Properties의 Opacity를 0으로 만들어서 투명화 시킨 것 같은데, 이에 대한 언급이 없다. 이거 보면서 Layout인줄 알고 여기에 OnClick 이벤트를 만들어서 했는데, 죽어라 해도 안되어서 엄청 해맸다. 이것저것 해본 결과 Layout의 OnClick 이벤트는 안 먹히는 이벤트 같다. 발동이 안된다;;;
아무튼 4일간의 뻘짓 결과 Layout은 OnClick 등과 같은 마우스 이벤트는 먹지 않는 것 같다는 결론을 내렸다.
이제 본격적으로 이야기 하고자 하는 것을 해보자.
위를 보면 Layout과 Rect가 Form 아래에 같은 계층이 있고, Layout 아래에 3개의 Layput과 ListBox가 있는 것이 보일 것이다.
여기서 말하고자 하는 것은 다음과 같다.
LayoutMain.BringToFront(); 하고,
RectLayoutBG.BringToFornt();를 하면...
바닥에 깔리는것인 LayoutMain 이고, 그 위에 RectLayoutBG가 깔려 최상위에 RectLayoutBG가 올라 오게 된다.
문제는 여기서 발생한다.
만약 이렇게 했다면 어떻게 될까?
LayoutMain.BringToFront(); 하고,
RectLayoutBG.BringToFornt(); 를 한 다음에
LayoutPopupClose.BringToFront(); 를 하였다면,
가장 위에 깔린 컴포넌트가 무엇인지 알 수 있을까?
여기서 답은 RectLayoutBG이다.
즉, LayoutPopupClose의 BringToFront는 어디까지나 LayoutMain 내의서의 BringToFront 인 것이다.
LayoutMain의 내부에서 가장 최상위에 보여지는 것이 LayoutPopupClose가 맞지만,
Form전체에서는LayoutPopupClose가 아닌 RectLayoutBG이 된다.
그래서 LayoutPopupClose가 FormMain 아래에 있었다면, 위에 설명한것과는 다르게 LayoutPopupClose가 되었을 것이다. 하고자 하는 말은 바로 이것이다.
같은 계층내에 있는 것 끼리만 BringToFront, SendToBack 의 순위가 결정되고, 자신의 계층별 부모의 순위에 의존해서 자신의 전체 순위가 결정된다.
이걸 몰라서 엄청 해맸었다. 이걸 알고 나니 험프리님이 lytSidebarHelper 언급하신 "사이드바 헬퍼를 구성할때 Z-Order(같은 자식간의 정렬순서, 즉 어떤 컨트롤이 위에 표시될지 여부)를 이용해 사이드바가 사이드바 헬퍼의 위에 위치하도록 해야합니다."를 이해하게 되었다.
덧. 여기서 언급한 계층이라는 용어는 정확한 용어가 Z-Order라는걸 오늘에서야 알았다.