IT/Delphi2009. 6. 1. 09:05
http://cbuilder.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_tip&no=883

장성호님의 글입니다.


Design-time때  Form의 FormStyle을 fsStayOnTop으로 설정하고
해당Form을 Show또는 ShowModal해보면

실제로 StayOnTop이 적용이 안된다는 질문이 커뮤니티에 심심찮게 올라옵니다.

비슷한 팁들이 여러가지 있던데... 정확한 원인과 증상에 대한 설명은 잘 없더군요
제가 올린 답변글에서도 마찬가지구...


오늘 일때문에 간단히 테스트 해보았는데...
정확한 이유에 대해서는 설명을 못하겠지만.
증상과 해결방안에 대해서 좀 기술해 보겠습니다.


Form의 FormStyle을    fsStayOnTop으로 설정하면

Form이 생성될때 TCustomForm의 CreateWnd함수에서 다음과 같은 코드가 실행됩니다.

       
  1. procedure TCustomForm.CreateWnd;   
  2. var  
  3.   ClientCreateStruct: TClientCreateStruct;   
  4. begin  
  5.   inherited CreateWnd;   
  6.   if NewStyleControls then  
  7.     if BorderStyle <> bsDialog then  
  8.       SendMessage(Handle, WM_SETICON, 1, GetIconHandle) else  
  9.       SendMessage(Handle, WM_SETICON, 10);   
  10.   if not (csDesigning in ComponentState) then  
  11.     case FormStyle of  
  12.       fsMDIForm:   
  13.          ...   
  14.       fsStayOnTop:   
  15.         SetWindowPos(Handle, HWND_TOPMOST, 0000, SWP_NOMOVE or  
  16.           SWP_NOSIZE or SWP_NOACTIVATE); // 팁과 똑같은 방식으로 설정함    
  17.     end;   
  18. end;  



stayontop관련 팁들을  보면 대게
SetWindowPos( Handle , HWND_TOPMOST, ...) 를 하라고 되어있죠

그런데 이렇게 한후에 Form을 Show 하면
Application(프로그램)내에서는 해당폼이 top으로 뜹니다.

그런데 전체 desktop에는 적용이 안되죠

제가 이해한 것은 Form이 Visible=true일때랑 false일때
SetWindowPos(Handle, HWND_TOPMOST ... 이 다르게 먹는다는것입니다.


그럼
Form을 데스크탑 전체에 topmost로 항상띄우려면 어떻게 해야할까요?

Form의 OnShow이벤트에서
SetWindowPos(Handle, HWND_TOPMOST...해주면 됩니다.
       
  1. procedure TForm2.FormShow(Sender: TObject);   
  2. begin  
  3.     SetWindowPos(Handle, HWND_TOPMOST, 0000, SWP_NOMOVE or  
  4.             SWP_NOSIZE or SWP_NOACTIVATE);   
  5. end;  


FormStyle을 그냥 fsNormal로 둬도 상관없구요

Form이 만약 hide되었다가 다시 Show할때 topmost가 해제 되기때문에
매번 Form이 show될때마다 SetWindowPos(Handle, HWND_TOPMOST...를 해줘야 합니다.


그런데...
Form을 Show했을때랑 ShowModal했을때 TopMost가 다르게 동작하는 부분도 있더군요

ShowModal로 했을경우엔 위와같이 Form의 OnShow에서
한번 SetWindowPos(..HWND_TOPMOST...)해주면 되는데..

그냥 Show로 할경우 현재프로그램의 다른 Form으로 포커스를  이동할경우엔 문제없지만
다른프로그램으로 이동하면 topmost가 풀려버립니다.

이경우 현재프로그램이 Deactivate 될때 TopMost폼을 다시  ToopMost로 Set해주면 되더군요
다음과 같이...

       
  1. procedure TForm1.FormCreate(Sender: TObject);   
  2. begin  
  3.   Application.OnDeactivate:=AppDeactivate;   
  4. end;   
  5.   
  6. procedure TForm1.AppDeactivate(Sender: TObject);   
  7. begin  
  8.   if Form2.Visible then  
  9.   begin  
  10.     SetWindowPos(Form2.Handle, HWND_TOPMOST, 0000, SWP_NOMOVE or  
  11.       SWP_NOSIZE or SWP_NOACTIVATE );   
  12.   end;   
  13. end;  



참 그리고 만약 top속성을 변경하고 싶다고
그리고 run-time에 FormStyle을 변경하는 경우가 있는데...
이것도 별로 바람직하지는 않습니다.
임프님이 작성한 팁에  나와있듯이 Form이 한번 껌벅거릴것입니다.
http://cbuilder.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_tip&no=32
FormStyle을 변경할때 CreateWindow를 다시 하기때문이죠

윈도우 핸들을 따로 저장해뒀다 .. 뭐시기 하는경우 문제가 발생할수 있겠죠
그리고 Form위의 다른 window-control도 모두 CreateWindow를 다시 하기때문에 매우 좋지 않습니다.

간만에 팁을 올렸네요
요즘 회사일이 바쁘기도 하구...
개인적으로 운영하는 카페도 신경쓴다구... 볼포에는 Q&A만 주로 하네요..

그럼..
Posted by 비와바람