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 로 하면 잘되는듯 한데..
이경우 작업표시줄에 버튼이 나타나구..
여튼 위 방법도 완벽하진 않네요..