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
[824] [MessageBox] ShowMessage에 대해..
장성호 [nasilso] 14039 읽음    2008-11-26 12:28
ShowMessage로 메세지박스를 보여주려고 하면

아주 가끔

원치않게 다른폼뒤에 메세지 박스가 뜬다던가?
또는 Top폼이 바뀌면서 메세지 박스가 뜬다던가 하는 현상이 있습니다.

얼마전 델마당에도 질문이 올라왔었구
어제 포럼에도 올라왔네요

http://www.delmadang.com/community/bbs_view.asp?bbsNo=17&bbsCat=0&st=&keyword=&indx=408159&keyword1=&keyword2=&page=18
http://cbuilder.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_qna&no=55272


개인적인 경험으로 저런 현상이 나타나는 원인을 집어보면..

[원인s]

원인1. ShowMessage로 뜬 메세지박스보다 일반폼이 나중에 Show되는 경우
 
   무엇인가 설정하면서 메세지박스가 떴는데...
   그상태에서 무슨 이벤트가 발생하여 ( 네트워크로 무슨 정보가 온다던가 , timer에 이벤트가 있다던가)
   Form을 Show해주면
   나중에 Show한 폼이 메세지박스보다 앞에 뜹니다.

void __fastcall TForm1::Button2Click(TObject *Sender)
{
    Timer1->Enabled=true;
    ShowMessage("Form2가 앞에 뜰까 ShowMessage가 앞에 뜰까?");
}
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
    Timer1->Enabled=false;
    Form2->Show();
}
 

  위와같은 경우 메세지박스가 뜬후 메세지박스위에 Form이 뜨게 됩니다.
  위 코드는 억지로 그런 현상을 만든것인데 저런현상이 생각보다 종종 있더군요
  

원인2.   WndParent가 Application->Handle이 아닌경우에..
 
  VCL에서 모든 폼은 윈도우핸들 생성시에 설정하는
  CreateParams의 WndParent 가 기본적으로는 Application->Handle 이 됩니다.
  (MDI Child폼 빼구)

  그런데 메신져처럼 대화창을 작업표시줄에 표시하고 싶다면
  Form의 CreateParams에서
  WndParent를 GetDesktopWindow() 로 바꿔주면 되죠

   그런데 문제는 WndParent를 DesktopWindow로 바꾼 Form에서
   ShowMessage를 호출하면
  
  WndParent가 Application->Handle인 폼이 앞으로 나오고 그 앞에 메세지박스가 뜹니다.


void __fastcall TForm1::Button2Click(TObject *Sender)
{
    Form2->ShowModal();
}
//=================================================================
void __fastcall TForm2::CreateParams(TCreateParams &Params)
{
    TForm::CreateParams(Params);
    Params.WndParent= GetDesktopWindow();
}
void __fastcall TForm2::Button2Click(TObject *Sender)
{
    ShowMessage("이 메세지박스는 어디에 뜰까?");
}


  이 경우에는 Form2에서 띄운 메세지 박스는 Form1위에 뜨고
  메세지박스가 Form2에 가려져 보이지 않게될수도 있습니다.
  Form2가 Modal로 뜬 상황이니..
  메세지박스을 앞으로 가져올수도 없는 상황이되죠..


기타 원인..
  
   그밖에도 잘모르지만 여러가지 원인이 있을수 있을것 입니다.


[문제해결을 위해 알아야 할것]

먼저 알아야 할 사실을   사실은

1. ShowMessage로 띄우는 메세지박스는 Win32 api  MessageBox로 띄우는 윈도우와 다른놈입니다.
    그냥 다른놈이 아니라 TForm을 상속받은 TMessageForm을 ShowModal로 띄워주는것 뿐이라는 사실입니다.

   Dialogs 유닛에 보면  다음과 같이 선언되어있죠!

   TMessageForm = class(TForm)

   그러니 TForm1  , TForm2 같이 TForm을 상속받은폼이나 TMessageForm이나 비슷한놈인게죠


2. 두번째 CreateParams 에 정해주는 WndParent 가 뭐냐는 것입니다.
   //
   이놈은  실제 Form의 윈도우핸들을 생성할때 사용하는 API인 CreateWindowEx 함수의
   9번째 들어가는 파라메터로 부모윈도우를 나타내는 것입니다.  
   http://www.winapi.co.kr/reference/Function/CreateWindowEx.htm

   VCL( C++빌더 또는 Delphi) 에서는 기본적으로
    Applicaiton->Handle의 부모윈도우는  Desktop윈도우이구
    다른 모든 Form의 부모윈도우(hWndParent)는 Applicaiton->Handle 이 됩니다.

    참조 http://serious-code.net/moin.cgi/Scrap_2fInsideTheVcl_2fPart3

    SetPaent로 정해주는 부모윈도우와는 좀 개념이 다르죠

    SetParent로 정해주는 parent는  -  보여주는 영역과 관련있다고 생각할수 있구요
    CreateWindowEx 에서 정해주는 wndParent는 -  보여주는 위치(Z-Order)와 관련있다고 할수 있습니다.


결론적으로 메세지박스및 폼이 뜨는 위치는 모두 Z-Order와 관련된 문제입니다.

     Form의 Style을 StayOnTop으로 설정해주는것도 Z-Order 문제이구요
     Z-Order 때문에 ShowMessage, MessagBox,Form등 모든윈도우가 원하는 위치(z-order)에 뜨지 않고
     엉뚱한 위치(Z-Order)에 뜰수 있는것이죠


[해결방법]


원인을 이해 했으니 해결방법도 Z-Order를 어떻게 조절해줄수 있을까 하는 관점에서 찾아나가시면 될것입니다.

해결방법1.

먼저 위에 원인2번과 같은 경우에
개인적으로 ShowMessage를 새로 만들어서 사용하기도 합니다. (ShowMessageEx)
Dialog 유닛에 있는 소스를 참조하여 TMessageFormEx 를 만들어 사용하는데
TMessageFormEx 에서 CreateParams의  WndParent를 Application->Handle로 하지 않고
Screen->ActiveForm->Handle로 하도록 만들어 사용합니다.

이렇게 하면 항상 현재 ActiveForm 이 WndParnet 가 되기때문에
Active된 폼에서 ShowMessageEx를 호출할때 메세지박스가 현재폼보다는 항상 앞에뜨게 되죠

또는 그냥 win32api  MessageBox를 씁니다.

MessageBox 함수의 첫번째 인자가 WndParent 가 되므로
MessageBox(this->Handle , ******) ;
이런식으로 사용하죠


해결방법2.
   원인1과 같은 경우는
   Screen객체의 OnActiveFormChange 이벤트 핸들러를 이용합니다.

   OnActiveFormChange이벤트는 말그대로  Active된 폼이 바뀔때 발생합니다.
   ShowMessage로 메세지박스를 띄우면 TMessageForm이 뜨게 되는데
   이때 Screen의 OnActiveFormChange 이벤트가 발생하게 되죠

   이 이벤트에서 TMessageForm의 Z-Order를 TopMost로 설정해주면
   어떤 폼보다 앞에 뜨게 됩니다.
   (단점 다른프로그램이 Active되어도 그 앞에 뜰수가 있습니다. StayOnTop처럼)

//c++builder
void __fastcall TForm1::FormCreate(TObject *Sender)   
{    
    Screen->OnActiveControlChange=OnScreenActiveFormChange;   
}   
//---------------------------------------------------------------------------   
void __fastcall TForm1::OnScreenActiveFormChange(TObject *Sender)   
{   
    if( Screen->ActiveForm!=NULL)   
    {   
        String sClsName=Screen->ActiveForm->ClassName();   
        if(sClsName=="TMessageForm")   
            SetWindowPos(Screen->ActiveForm->Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);   
    }   
}   
//---------------------------------------------  
void __fastcall TForm1::Button1Click(TObject *Sender)   
{   
    ShowMessage("이 메세지 항상 Top으로 뜨나?");   
}   


//delphi
procedure TForm1.FormCreate(Sender: TObject);    
begin    
  Screen.OnActiveFormChange:=OnScreenActiveFormChange;    
end;    
  
procedure TForm1.OnScreenActiveFormChange(Sender: TObject);    
begin    
  if Assigned(Screen.ActiveForm) and (Screen.ActiveForm.ClassName='TMessageForm') then    
      SetWindowPos(Screen.ActiveForm.Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE);    
end;   
 
  
이상입니다.
그럼..
장성호 [nasilso]   2010-11-23 17:32 X
ShowMessage함수에서

RAD2007까지는 TMessageForm을 이용하는데..
RAD2010에서는 전혀 다른 방식으로 동작하는듯 하네요(rad2009는 확인해 보지 못함)

rad2010에서는 위와같은 현상이 잘 나지 않을듯 합니다.(아직 격어보지 못해서..)

+ -

관련 글 리스트
824 [MessageBox] ShowMessage에 대해.. 장성호 14039 2008/11/26
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.