【易语言WinAPI】托盘菜单窗口焦点问题-解决G&SetForegroundWindow

今天一位我的易语言讨论群一位群友**@爱易♀棉儿**遇到了一个问题,在群里提问,我顺道也就参与进去了。

最后差不多也了解了情况,程序主要属于资源集合,集合了很多计算机、编程相关的教程资料,比较注重界面UI设计,作者**@爱易♀棉儿**设计界面就花了很长的时间,这认真追求极致的精神确实值得我们学习。

程序现在还没有正式制作完成,在其正式发布后,如果作者同意发布分享,一定会把程序在我的博客当中分享给大家的 (^_^)。

回到正题,问题是出现在托盘菜单上面。

因为比较注重界面UI,所以包括右下角的托盘菜单都用了一个单独的窗口做菜单,右键单击托盘图标就弹出菜单,里面选项就不用多说了,就是一些常用的功能啦,退出程序、联系我们之类的。

而问题就出在这个窗口载入完毕以后没办法消失,因为既然是一个弹出菜单,所以在鼠标点击其他地方的时候,这个菜单窗口应该就要消失了,在易语言中一般都是通过销毁窗口或者将窗口可视属性设置为假两种方法,这个程序使用的的是前者的方式。

首先我想到的就是通过窗口焦点来判断鼠标是不是点击了其他地方。

很荣幸的,她把这个比较保密的源码发给了我,虽然是一个未成品,功能都还没有做全,不过可以看出界面已经做得非常完美几乎就是成品了。

拿到源码后便开始分析了,才发现并没有那么容易,测试了很多次,发现菜单窗口载入以后直接就依次产生了获取焦点和失去焦点的事件,接着点击其他地方并不会产生失去焦点的事件,只有在程序的主窗口上点击才会产生这个事件。

为什么主窗口能够得到菜单窗口是否失去了焦点,而在系统其他地方单击却没办法获取?这个原因我也不清楚,大概应该是前者在自身,后者在身外的原因吧,也就是“没有特权”导致吧。当然这只是大概猜想,具体的原因可能因为我知识积累不够没办法确定。

本来是打算放弃了,因为其实还可以通过另一种方式实现同样的效果,尝试多次无果,本打算放弃,所以就想不在一棵树上吊死,换一种非常相似的办法来实现,也就是窗口加载完成以后加入一个死循环,不断获得系统当中最顶端的窗口来判断窗口是不是已经不在最前面了,可是接下来却还真的就发现了问题所在。

这里死循环不断获得系统顶端窗口用到的API是百度得来的,也就是 GetForegroundWindow,函数原型是: HWND GetForegroundWindow(void);

大概写法我重新写了一遍,如下图:

通过死循环线程不断的调试输出顶端窗口,发现这个菜单窗口加载完毕以后系统最顶端的窗口就已经不是这个窗口了,而只有手动用鼠标点击一下窗口空白的地方才能把系统最顶端的窗口变为这个程序的窗口,这样窗口才能够获取焦点,接着再通过窗口失去焦点的事件来适时关闭。

接下来便恍然大悟,既然最终的原因是窗口载入完毕后自动失去焦点导致没办法再次产生失去焦点的事件,那么只需要在载入完毕自动失去焦点变成非顶端窗口,那么再让窗口获取焦点变成顶端窗口不就好了吗?

接下来就是应该怎么设置窗口为系统顶端窗口了,我想既然有GetForegroundWindow函数,自然就有一个SetForegroundWindow咯,试了一下确实如此,所以被我折腾了很久的源码被我删掉了,直接在接收过来的压缩包中重新解压了源码,然后在窗口载入完毕的最后一行加入了一行命令【SetForegroundWindow(取窗口句柄())】,测试效果……Perfect~Over~~

再从头到尾想一想,之所以在托盘右键单击并载入菜单窗口的时候窗口会立刻失去焦点,原因就是焦点被转移到了任务栏的窗口句柄上面,任务栏也算是一个窗口,右键单击的时候菜单窗口载入暂时性的获取了顶端的位置,可是接下来任务栏因为要在最前,所以又把顶端窗口的位置给抢回来了,这样菜单窗口自然就失去了焦点,所以我们的原理就是在任务栏夺回去以后再把顶端句柄给夺回来。

文章写得很随便,大家也就随便的看看就好了,同时精力、时间及水平有限,很多地方可能出现一些错误或者其他问题,还请大家见谅。希望大家能够多多支持这个新开的博客~~~