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
[883] [Forms] FormStyle의 StayOnTop 문제점
장성호 [nasilso] 12118 읽음    2009-04-13 18:28
Design-time때  Form의 FormStyle을 fsStayOnTop으로 설정하고
해당Form을 Show또는 ShowModal해보면

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

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


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


Form의 FormStyle을    fsStayOnTop으로 설정하면

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

procedure TCustomForm.CreateWnd;
var
  ClientCreateStruct: TClientCreateStruct;
begin
  inherited CreateWnd;
  if NewStyleControls then
    if BorderStyle <> bsDialog then
      SendMessage(Handle, WM_SETICON, 1, GetIconHandle) else
      SendMessage(Handle, WM_SETICON, 1, 0);
  if not (csDesigning in ComponentState) then
    case FormStyle of
      fsMDIForm:
         ...
      fsStayOnTop:
        SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or
          SWP_NOSIZE or SWP_NOACTIVATE); // 팁과 똑같은 방식으로 설정함 
    end;
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...해주면 됩니다.
procedure TForm2.FormShow(Sender: TObject);
begin
    SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or
            SWP_NOSIZE or SWP_NOACTIVATE);
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해주면 되더군요
다음과 같이...

procedure TForm1.FormCreate(Sender: TObject);
begin
  Application.OnDeactivate:=AppDeactivate;
end;

procedure TForm1.AppDeactivate(Sender: TObject);
begin
  if Form2.Visible then
  begin
    SetWindowPos(Form2.Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or
      SWP_NOSIZE or SWP_NOACTIVATE );
  end;
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만 주로 하네요..

추신 - 09-12-16
MainForm이 아닌 subForm을 topmost로 하려고 할땐..
위 방법이 먹히지 않는 경우가 있네요..

왜 그러냐 하니.. 모든 form의 CreateParams에서  wndParent는
Application.Handle이 되는데.. Application.Handle이 topmost가 아닌 상태에서
subform을 적용해도 잘 되지 않는 것 같습니다.

subform의 CreateParams에서  wndParent를  0 로 하면 잘되는듯 한데..
이경우 작업표시줄에 버튼이 나타나구..

여튼 위 방법도 완벽하진 않네요..
DCAS [simulica]   2009-04-20 16:38 X
감사합니다.
이홍규 [antonio24]   2009-05-25 17:00 X
좋은 정보 감사합니다~ ^_^
nansama [nansama]   2010-01-13 11:54 X
참고로 sub-Form을 TOPMOST 속성으로 보이게 하려면 Form class의 CreateParams 함수를 오버라이드 해서
부모 핸들을 데탑으로 설정 하면 되더군여 저는 한참 삽질을 해서 ...ㅋㅋ
Params.WndParent = GetDesktopWindow();
아래 임프님 설명을 참고 해서 성호님꺼랑 합쳐 보세요..
http://cbuilder.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_tip&no=18
leo21c [leo21c]   2012-11-21 17:07 X
감사합니다. Windows 7 64bit에서만 PrinterSetupDlg에서 프린터 설정 후에 뒤로 사라지는 문제가 있었는데 이거 처리하고 해결이 되었습니다.

+ -

관련 글 리스트
883 [Forms] FormStyle의 StayOnTop 문제점 장성호 12118 2009/04/13
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.