허.. 아래 훔쳐온? 긁어온? 팁을 올리고 나서.. 너무 쪽팔려서요.
실추된 명예를 되살릴 멋진 팁이 없을까.. 하고 곰곰히 생각해보다가..
오래전에 연습삼아 만들었던 소스들중에서, 아주 멋지진 않지만 그래도 재미있는 걸
하나 찾아서 올립니다. 사실 옛날에 한번 언급하긴 했습니다만(1457번),
드래깅만 설명하고 리사이즈에 대해선 설명하지 않았거든요. ^^;;;;
자아.. 그럼 얘기를 풀어볼까요.
윈도우즈 메시지중 WM_SYSCOMMAND 메시지를 보면, 윈도우 자체의 동작에 관한
기능들을 하는 메시지란 것을 알 수 있습니다. 닫기, 스크롤, 사이즈변경 등등의
기능이 이 메시지의 옵션(WPARAM 인자)를 통해서 이루어집니다.
그런데, 사실 이 메시지에는 win32 api 레퍼런스에서 언급하지 않은 몇가지의
옵션이 더 있습니다. 그중의 하나가 위에서 언급한 오래전의 팁에서 언급했던
런타임 드래깅.. 0xf12구요. 그외에 여덟개의 옵션이 더 있죠.
이 여덟개의 옵션은 각각 윈도우를 위쪽경계 / 아래경계 / 오른쪽경계 / 왼쪽경계
/ 위왼쪽끝 / 위오른쪽끝 / 아래왼쪽끝 / 아래오른쪽끝 / 의 여덟개의 방향에서
클릭하고 드래그했을때 WM_SYSCOMMAND 메시지가 발생하면서 WPARAM으로 넘어오는
것입니다.
다시 말하면, 윈도우 핸들을 가지는 컨트롤이라면 강제로 이 여덟개의 옵션을
사용해서 런타임에 드래깅을 통해 리사이즈할 수 있다는 말이 되죠.
길게 설명할 시간은 없고.. 잘 이해가 안되시는 분은, 위의 짤막한 설명을 한번
더 읽어보시든지, 아래 소스를 읽어보시고 직접 실행해보시기 바랍니다.
여덟개나 되는 값을 일일이 값만으로 기억하긴 뭣하니까 매크로로 선언해봅시다.
#define SC_DRAG_RESIZEL 0xf001 // left resize
#define SC_DRAG_RESIZER 0xf002 // right resize
#define SC_DRAG_RESIZEU 0xf003 // upper resize
#define SC_DRAG_RESIZEUL 0xf004 // upper-left resize
#define SC_DRAG_RESIZEUR 0xf005 // upper-right resize
#define SC_DRAG_RESIZED 0xf006 // down resize
#define SC_DRAG_RESIZEDL 0xf007 // down-left resize
#define SC_DRAG_RESIZEDR 0xf008 // down-right resize
#define SC_DRAG_MOVE 0xf012 // move
하는김에, 전에 설명했던 드래그 옴션인 0xf012까지 함께 선언했습니다.
그담에.. 폼에 패널을 하나 놓고, 패널의 OnMouseMove 이벤트의 핸들러를 작성합니다.
void __fastcall TForm1::Panel1MouseMove(TObject *Sender, TShiftState Shift,
int X, int Y)
{
TControl *SenderControl = dynamic_cast(Sender);
if((X < 4 && Y < 4) :: (X > SenderControl->Width-4 && Y > SenderControl->
Height-4))
SenderControl->Cursor = crSizeNWSE;
else if((X < 4 && Y > SenderControl->Height-4) :: (X > SenderControl->
Width-4 && Y < 4))
SenderControl->Cursor = crSizeNESW;
else if(X < 4 :: X > SenderControl->Width-4)
SenderControl->Cursor = crSizeWE;
else if(Y < 4 :: Y > SenderControl->Height-4)
SenderControl->Cursor = crSizeNS;
else
SenderControl->Cursor = crDefault;
}
위 이벤트 핸들러는, 단순히 커서의 위치에 따라 커서모양만 각 상황에 맞는
리사이즈 커서로 바꾸어준거구요.
중요한 것은 아래 부분입니다.
이번엔, 이 패널의 OnMouseDown 이벤트의 핸들러를 작성합니다.
void __fastcall TForm1::Panel1MouseDown(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
TControl *SenderControl = dynamic_cast(Sender);
int SysCommWparam;
if(X < 4 && Y < 4)
SysCommWparam = SC_DRAG_RESIZEUL;
else if(X > SenderControl->Width-4 && Y > SenderControl->Height-4)
SysCommWparam = SC_DRAG_RESIZEDR;
else if(X < 4 && Y > SenderControl->Height-4)
SysCommWparam = SC_DRAG_RESIZEDL;
else if(X > SenderControl->Width-4 && Y < 4)
SysCommWparam = SC_DRAG_RESIZEUR;
else if(X < 4)
SysCommWparam = SC_DRAG_RESIZEL;
else if(X > SenderControl->Width-4)
SysCommWparam = SC_DRAG_RESIZER;
else if(Y < 4)
SysCommWparam = SC_DRAG_RESIZEU;
else if(Y > SenderControl->Height-4)
SysCommWparam = SC_DRAG_RESIZED;
else
SysCommWparam = SC_DRAG_MOVE;
ReleaseCapture();
SendMessage(Panel1->Handle, WM_SYSCOMMAND, SysCommWparam, 0);
}
ReleaseCapture()함수에 대한 것은 위에 언급한 저번 팁에서 간단히 언급했었던것
같습니다. 궁금하신 분은 참고하시길.
이 소스를 실제로 실행해보면.. 신기하게도, 폼위에 놓여진 패널이, 마치
독립적인 윈도우처럼 드래깅 될 뿐 아니라, 바깥쪽 경계를 드래그해서 리사이즈도
할 수 있습니다.
별 도움이 안된다고 생각할 수도 있습니다만, 잘 응용하면 생각보다 아주
재미있게 활용할 수 있습니다. 실제로 제가 그렇구요.
오랜만에 올린 팁이 까마득히 오래전에 알아냈던 구닥다리 팁이라서 죄송합니다.
혹 다른 분들도 이미 이 방법을 아시고 있는 분들도 있을지..?
쩝.. 바쁜 시간을 좀더 쪼개어서라도 좀 화끈하게 재미있는 팁을 찾아보겠습니다..
분발하자 임프... ^^;;;;
임펠리테리 박지훈이었습니다.