扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
感悟VB细水长流话API(六-1)
第八话 父与子
在开始这一话之前,不知各位读者有没有使用过MDI Form呢?看看图1,这是一个标准的MDI Form和其中一个子窗体在标准和最大化情况下的外观。不过别误会,我不是想讲MDI,你再看看图2,我只是想让你区别图2的窗体不是MDI Form。图2的两个窗体都是一般的窗体,从最大化的外观就可以看出区别了。是不是觉得很有意思?其实也没有什么秘密。
我说过Windows中多数东西都是一种窗口,比如按钮。一般情况下我们看到的按钮都是在一个窗体的里面,这是因为窗体和按钮有一种父与子的关系。当一个窗口成为另一个窗口的子窗口(Child),那么它的位置的变化就只发生在另一个窗口里,另一个窗口就是这个窗口的父窗口(Parent)。平时我们建立的窗体都是相互独立的,与其他的窗体没有关系,但我们可以通过API使它们建立起父与子的关系。这要用到SetParent:
Private Declare Function SetParent Lib "user32" (ByVal hWndChild As Long, ByVal hWndNewParent As Long) As Long
SetParent接收两个参数,第一个是将成为子窗口的窗口句柄,第二个是将成为父窗口的窗口句柄。它的使用很简单,比如想把Form2作为Form1的子窗口,只需这样使用:
SetParent Form2.hWnd, Form1.hWnd
Windows会自动把Form2在新的父窗口中的位置调整为原父窗口的位置(即使是桌面,也是一个父窗口)。即是说,假如原来在桌面的Form2,位置为10,10,则它在新的父窗口中的位置也为10,10。但这个新的10,10是以新父窗口为参照物的,无论怎么变化,都是在新父窗口中。
不过应该注意,并不是所有东西都适合当父窗口。因为每一种窗口都有为自己设计的行为,比如当画面重画时要画什么,如果我们为它添加了新的子窗口,那么它们将可能产生冲突,因为父窗口在设计时并没有考虑出现意外的子窗口的情况。为了说明这个问题,我做了一个示例。当我把按钮作为ListBox的子窗口时,你会看到由于ListBox在选择项目时进行了画面的重画,导致按 钮显示变得不正常,但当我按了一下按钮时,又因为按钮的重画,显示又正常了。
值得一提的是,当我们把Form1中的一个子窗口(比如按钮)放置到Form2中,而我们又在Form1中为这个子窗口的某个事件写了执行代码,那么它还会被执行吗? Form2又需不需要为这个新的子窗口做特别处理呢?假如我的处理代码都是写在Form1中的,而所有控件都被我放到Form2中时(如图4),它们的点击事件的代码仍然能被执行。由于无法得知实际上VB内部是如何处理控件的消息循环的,所以我也无法对此中秘密进行解释,特别是一个应该注意的问题——当你把按钮(这里以按钮为例,但其实其他东西也一样)放到Form2中后,如果这个按钮在Form2中获得了焦点,那么你就无法从Form2切换回Form1,除非这时你可以让Form1中某个控件重新获得焦点——比如通过使某个控件从Form2中成为Form1的子窗口,或者使用 SetFocus让Form1的某个控件获得焦点。所以,实际应用中应该避免这种情况的发生。如果新的父窗口不是由VB所建立的窗体,那么这种事就不会发生,不过这已不是本话的内容了。
在我写的示例源程序里,还有一个GetParent的API这里没有讲到,我用它判断当前的子窗口是哪个窗体的子窗口。它的作用是返回指定子窗口的父窗口的句柄。
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者