C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C++빌더 팁&트릭
C++Builder Programming Tip&Tricks
[746] [Forms] MDI 폼에서 배경넣기 3 - 전혀 새로운 방법
장성호 [nasilso] 9442 읽음    2008-02-27 11:22
개인적으로는 이제는
어플리케이션을 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가 거의 쓰여지지 않는 요즘 얼마나 쓰임새 있을지....

그럼...

+ -

관련 글 리스트
746 [Forms] MDI 폼에서 배경넣기 3 - 전혀 새로운 방법 장성호 9442 2008/02/27
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.