개인적으로는 이제는
어플리케이션을 MDI 폼으로 짜는 경우가 거의 없지만...
혹누군가에게 필요할지도 모르고
또 예전에 이것때문에 좀 고생한것이 생각나서.... 올려봅니다.
[기존에 방식]
기존에 mdi폼에 배경을 넣는 방법은
대게 MDI폼의 ClientHandle의 dc에다가
WM_PAINT , WM_ERAZBKGND , WM_RESIZE 등의 메세지에
그림을 그려줬었다.
http://cbuilder.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_tip&no=357
http://cbuilder.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_tip&no=647
[새로운방식]
이방법은 그냥 폼에 TImage올려놓고 이미지파일 Load해놓으면 폼의 배경이 되듯이
그런 방식으로 구현하는것입니다.
1. MDI폼위에 Panel을 하나 올려놓습니다.
2. Panel위에 TImage를 하나 올려놓습니다. , 그리고 배경으로 원하는 이미지를 Load합니다.
3. MDI폼의 OnCreate에 Panel의 Paret을 MDI폼의 ClientHandle로 바꿉니다.
이는 ClientHandle은 TControl의 아니므로 SetParent로 바꿔야 하는데
VCL에서는 ParentWindow라는 인터페이스를 제공해줍니다.
void __fastcall TForm1::FormCreate(TObject *Sender)
{
Panel2->Parent=NULL;
Panel2->ParentWindow=this->ClientHandle;
}
이렇게만 하면 Panel2가 MDI폼의 배경으로 들어갑니다.
<여기까지만했을때 문제점>
MDI Child폼의 띄우고 Child폼과 Panel을 번갈아 클릭하면
Panel이 위해 올라왔다가 .. Child폼이 위로 올라왔다가 ...왔다갔다 합니다.
항상 Panel이 아랫쪽에 있게 하고싶은데....
4. Panel이 항상 MDI-Client폼 아랫쪽에 있게 하는 방법은?
4-1. Panel의 Enabled = false 해주면 됩니다.
void __fastcall TForm1::FormCreate(TObject *Sender)
{
Panel2->Parent=NULL;
Panel2->ParentWindow=this->ClientHandle;
Panel2->Enabled=false;
}
; 이렇게 하면 Panel은 항상 MDI-Client폼 아랫쪽에 있게 됩니다.
4-2 그런데 Panel위에 Button을 올려놓고 Click도 하고싶다면 4-1방법으로는 안되겠죠
Panel의 Enabled=true이면 Panel도 MDI 폼에서 MDI-Client 중에 하나와 비슷하게 돌아가는데....
여기서 좀 고생했는데... 의외로 쉬운 방법이 있더군요
Panel이 Active될때 SendToBack으로 맨뒤로 보내버리면 되더군요
void __fastcall TForm1::FormCreate(TObject *Sender)
{
Panel2->Parent=NULL;
Panel2->ParentWindow=this->ClientHandle;
// Panel2->Enabled=false;
Panel2->DoubleBuffered=true;
OrgPanelProc=Panel2->WindowProc;
Panel2->WindowProc= PanelMsgProc;
}
//-------------
void __fastcall TForm1::PanelMsgProc(TMessage &Msg)
{
if(Msg.Msg==WM_CHILDACTIVATE)Panel2->SendToBack();
OrgPanelProc(Msg);
}
이렇게 하면 Panel위에 여러가지 원하는 Control을 마음대로 올려서 사용해도 전혀 문제 없습니다.
5.그런데 목적은 MDI폼의 배경이었죠?
MDI 폼이 크기가 바뀌었을때 처리가 아직 안되었는데....
( WM_PAINT , WM_ERAZEBKGND .. 등은 TPanel과 TImage가 알아서 처리함)
5-1 . MDI폼의 Resize이벤트에 배경 조정
void __fastcall TForm1::FormResize(TObject *Sender)
{
TRect rc;
if(GetWindowRect(ClientHandle,&rc))
{
Panel2->Left=(rc.Width() -Panel2->Width)/2;
Panel2->Top=(rc.Height() -Panel2->Height)/2;
}
}
위와같이 하면 MDI폼의 한가운데 Panel이 위치하게 됩니다.
그런데 문제는 폼의 크기는 변경되지 않고 Client영역의 크기만 변경되었을때는
Client의 가운데에 Panel이 위치하지 않게 되죠
5-2. MDI폼의 Resize가 아니라 MDI-ClientHandle의 resize때 처리하면 정확합니다.
void __fastcall TForm1::FormCreate(TObject *Sender)
{
NewClient=(FARPROC)MakeObjectInstance(MDIClientProc);
OldClient=(FARPROC)SetWindowLong(ClientHandle, GWL_WNDPROC,(LPARAM)NewClient);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::MDIClientProc(TMessage &Msg)
{
Msg.Result = CallWindowProc(OldClient,ClientHandle, Msg.Msg , Msg.WParam,Msg.LParam);
if(Msg.Msg==WM_SIZE)
{
TRect rc;
if(GetWindowRect(ClientHandle,&rc))
{
Panel2->Left=(rc.Width() -Panel2->Width)/2;
Panel2->Top=(rc.Height() -Panel2->Height)/2;
}
}
}
이렇게 하면 ClientHandle의 Resize이벤트를 정확히 잡아서 처리할수 있습니다.
6. 정리하면 ..
void __fastcall TForm1::FormCreate(TObject *Sender)
{
Panel2->Parent=NULL;
Panel2->ParentWindow=this->ClientHandle;
Panel2->DoubleBuffered=true;
OrgPanelProc=Panel2->WindowProc;
Panel2->WindowProc= PanelMsgProc;
//--------------------------------
NewClient=(FARPROC)MakeObjectInstance(MDIClientProc);
OldClient=(FARPROC)SetWindowLong(ClientHandle, GWL_WNDPROC,(LPARAM)NewClient);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::MDIClientProc(TMessage &Msg)
{
Msg.Result = CallWindowProc(OldClient,ClientHandle, Msg.Msg , Msg.WParam,Msg.LParam);
if(Msg.Msg==WM_SIZE)
{
TRect rc;
if(GetWindowRect(ClientHandle,&rc))
{
Panel2->Left=(rc.Width() -Panel2->Width)/2;
Panel2->Top=(rc.Height() -Panel2->Height)/2;
}
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::PanelMsgProc(TMessage &Msg)
{
if(Msg.Msg==WM_CHILDACTIVATE)Panel2->SendToBack();
OrgPanelProc(Msg);
}
//---------------------------------------------------------------------------
위 방법은 MDI 배경에 그림만 넣는것이 아니라
원하는 Control을 마음대로 올려놓고 코딩도 가능한 방법입니다.
MDI가 거의 쓰여지지 않는 요즘 얼마나 쓰임새 있을지....
그럼...