注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

银河军团大本营

光荣的军团,永远的丰碑 <坚持原创>

 
 
 

日志

 
 

如何判断程序在最前面(或窗体在最上层)  

2013-11-15 21:57:37|  分类: 编程小技巧 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

  昨日再次发现自己多年前编写的一个简单音乐播放器在点击托盘区图标时表现得有些不太自然:如果播放器窗口可见,且位于其他窗口之后,按一般使用体验来说,此时应让窗口提前显示,而不是最小化。之前只是简单地判断程序是否最小化,如果最小化,则点击托盘区图标就显示窗口;否则就将播放器最小化到托盘区。

  简单的判断,导致使用体验不是太好,于是就想到用GetForegroundWindow/GetTopWindow等API函数来判断窗口是否在最前面(最上层),但测试后发现,在点击托盘区图标时用这些函数来判断都不合适,因为此时的最上层窗口可能是输入法窗口或托盘区及其相关窗口,而不是程序窗口本身!

  网上搜索的结果大多也是说通过GetForegroundWindow 来判断,但其应用范围有限。好在经过不断试验,得到以下代码,可以用来判断程序或窗口是否在最前面:

function isVclAppForm(h: THandle): Boolean;
var
r: TRect;
begin
GetWindowRect(h, r);
// check if TApplication Form (Width=0, Height=0)
Result := (r.Right = r.Left) or (r.Bottom = r.Top);
end;

function isTopMostWindow(h: THandle): Boolean;
begin
Result := WS_EX_TOPMOST = (GetWindowLong(h, GWL_EXSTYLE) and WS_EX_TOPMOST);
end;

function isTopWindow(AForm: TForm): Boolean;
var
h: THandle;
hTray: THandle;
begin
Result := False;
h := GetTopWindow(0);
hTray := FindWindow('Shell_TrayWnd', nil);
while (h <> 0) do begin
//跳过托盘区、不可见窗口、悬浮窗口、VCL TApplication所创建的隐含窗口
if (h = hTray) or IsChild(hTray, h) or not IsWindowVisible(h) or isTopMostWindow(h) or isVclAppForm(h) then begin
h := GetNextWindow(h, GW_HWNDNEXT);
end else begin
if h = AForm.Handle then begin
Result := True;
end;
Break;
end;
end;
end;

  不过,我在使用时需要判断当前程序窗口是否被其他窗口挡住,即需要判断不在最前面,于是有了以下代码:

function notCrossWithForm(AForm: TForm; h: THandle): Boolean;
var
r: TRect;
begin
GetWindowRect(h, r);
Result := (r.Right = r.Left) or (r.Bottom = r.Top) or // for TApplication (Width=0, Height=0)
(AForm.Left + AForm.Width <= r.Left) or (AForm.Left >= r.Right) or
(AForm.Top + AForm.Height <= r.Top) or (AForm.Top >= r.Bottom);
end;

function isTopMostWindow(h: THandle): Boolean;
begin
Result := WS_EX_TOPMOST = (GetWindowLong(h, GWL_EXSTYLE) and WS_EX_TOPMOST);
end;

function isNotTopWindow(AForm: TForm): Boolean;
var
h: THandle;
hTray: THandle;
begin
Result := False;
h := GetTopWindow(0);
hTray := FindWindow('Shell_TrayWnd', nil);
while (h <> 0) do begin
//跳过托盘区、不可见窗口、悬浮窗口、VCL TApplication所创建的隐含窗口、未遮住指定窗口的窗口 if (h = hTray) or IsChild(hTray, h) or not IsWindowVisible(h) or isTopMostWindow(h) or notCrossWithForm(AForm, h) then begin
h := GetNextWindow(h, GW_HWNDNEXT);
end else begin
if h <> AForm.Handle then begin
Result := True;
end;
Break;
end;
end;
end;

  经测试,以上代码使得程序有较好的使用体验,即:如果程序窗口最小化,则点击托盘图标就正常显示;如果程序窗口正常显示且位于最前面(指眼睛看到的效果),则点击托盘图标就最小化; 如果程序窗口正常显示且被其他正常窗口挡住(跳过一些眼睛看到的悬浮窗口),则点击托盘图标就将程序提前到最前面显示。 

  如果你还有更简单更好的方法,不要忘了告诉我哦^o^

  评论这张
 
阅读(1340)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018