【PB】调用 Win32 公共控件的改进方案

笔者在《用 Windows 公共控件增强 PB 应用的界面》一文中,曾经讨论过使得 PB 能支持较新的 Win32 公共控件的方法。当时提出了在应用对象的 Open 事件中用 InitCommonControlsEx 函数来代替 PB 自动调用的 InitCommonControls 函数,这种方法的缺点很明显:

  • 用户程序员必须关注 Win32 公共控件的初始化。用户程序员必须在应用对象的 Open 事件中调用InitCommonControlsEx 函数为一类控件初始化。
  • 在设计时期不能实现所见即所得。由于在设计时期,InitCommonControlsEx 函数可能未被调用,所以用户程序员将看不见控件效果。

在 PB9 进行 beta 测试之际,笔者和 Sybase 的程序员进行了探讨,提出了 3 个修改方案,分别为:

  1. 在PB的源代码中原先调用 InitCommonControls 的地方,删除调用 InitCommonControls 的代码,改成一个根据控件类名填充 INITCOMMONCONTROLSEX 结构的 switch…case 语句块,然后再调用 InitCommonControlsEx。这个方案对用户程序员来说最方便,但这样会迫使 Sybase 跟在 Microsoft 后面添加更多的 case ClassName 块来支持在不久将来推出的新控件。所以该方案被否决了。
  2. 将 INITCOMMONCONTROLSEX 结构的 dwICC 成员直接暴露在外,用户直接在属性标签页上设置该值。这会使实现细节暴露,不便于日后的代码修改,所以不宜采用。
  3. 在外部可视用户对象的 create 事件中调用 InitCommonControlsEx 函数进行控件初始化。该方案被最终采纳。它在不增加外部可视控件的开发者的工作量的情况下,省去了用户程序员和 Sybase 的麻烦!

在讨论 PB 的内部事件 Create 和 Destroy 之前,先熟悉一下 Source Editor。Source Editor 提供 PB 对象基于文本的定义。我们可以右击任何 PB 对象,在弹出菜单中选择 Edit Source 菜单项,来调用该功能。现以 w_demo 的源码为例进行讨论:

forward         /* 声明窗口及其内对象的继承关系 */
    
global  type w_demo from window
    end type
    type uo_1 from evuo_datetimepick within w_main  
/* evuo_datatimepick 使用的是 DataTimePick 控件 */
    end type
end forward
 
global  type w_demo from window   /* w_demo 的成员变量声明或定义 */
    integer width 
=   2533
    integer height 
=   1392
    boolean titlebar 
=   true
    
string  title  =   " Demonstration "
    boolean controlmenu 
=   true
    boolean minbox 
=   true
    boolean maxbox 
=   true
    boolean resizable 
=   true
    
long  backcolor  =   67108864
    
string  icon  =   " AppIcon! "
    boolean center 
=   true
    uo_1 uo_1
end type
global  w_demo w_demo
 
on w_demo.create     
/* Create 相当于 C++ 的构造函数 */
    MessageBox(
" w_demo " " 事件:Create( )~n(在创建uo_1之前) " )
    
this .uo_1  =  create uo_1     /* 创建 uo_1 对象 */
    MessageBox(
" w_demo " " 事件:Create( )~n(在创建uo_1之后) " )
    
this .Control[]  =  { this .uo_1}
end on
 
on w_demo.destroy     
/* Destroy 相当于 C++ 的析构函数 */
    MessageBox(
" w_demo " " 事件:Destroy( )~n(在删除uo_1之前) " )
    destroy(
this .uo_1)
    MessageBox(
" w_demo " " 事件:Destroy( )~n(在删除uo_1之后) " )
end on
 
event  open;MessageBox( " w_demo " " 事件:Open( ) " )
end 
event
 
event  close;MessageBox( " w_demo " " 事件:Close( ) " )
end 
event
 
type uo_1 from evuo_datetimepick within w_main  
/* uo_1 的成员变量的声明或定义 */
    integer x 
=   100
    integer y 
=   100
    integer taborder 
=   10
end type
 
event  constructor;call super::constructor;
    MessageBox(
" uo_1 " " 事件:Constructor( ) " )
end 
event
 
event  destructor;call super::destructor;
    MessageBox(
" uo_1 " " 事件:Destructor( ) " )
end 
event

在窗口 w_demo 上布放了一个外部可视用户对象 (External Visual User Object) uo_1,该对象实现了 Win32 公共控件 DateTimePick。在源码中的 MessageBox 函数调用是为了测试各个事件的执行次序而写的,同样在 evuo_datetimepick 对象源码的 create 和 destroy 事件中也有对 MessageBox 函数的调用。通过运行程序,我们可以获得如下的执行次序:

"w_demo" "事件:Create( )~n(在创建uo_1之前)"
"evuo_datetimepick" "事件:Create( )"
"w_demo" "事件:Create( )~n(在创建uo_1之后)"
"uo_1" "事件:Constructor( )"
"w_demo" "事件:Open( )"
"w_demo" "事件:Close( )"
"uo_1" "事件:Destructor( )"
"w_demo" "事件:Destroy( )~n(在删除uo_1之前)"
"evuo_datetimepick" "事件:Destroy( )"
"w_demo" "事件:Destroy( )~n(在删除uo_1之后)"

通过上表,可以肯定 Create 和 Destroy 的功能和 C++ 的构造函数和析构函数一样。由于有这样的认识,笔者就假设外部可视用户对象的 Create 事件的执行早于对 CreateWindowExA 函数的调用。因而,在外部可视用户对象的 Create 事件中加入对 InitCommonControlsEx 函数的调用,可让对象在设计时期就所见即所得。以 evuo_datetimepick 为例,修改代码如下:

on evuo_datetimepick.create
    stc_initcommoncontrolsex InitCtrls

    InitCtrls.dwSize 
=   8
    InitCtrls.dwICC 
=   256
    InitCommonControlsEx(InitCtrls)
end on

保存以后,无论何时在窗口上布放该对象都正常显示。

此外,Source Editor 对处理继承引起的编译错误很有效。如果在父类对象中删除了一个控件,但派生类中引用了该控件,则派生类因编译错误而不能打开。以往只能用版本控制来恢复,然后先注释掉派生类中的引用,然后删除父类中的控件。现在用 Source Editor 则可以直接编辑派生类,并改正之。同样,通过修改跟从在 from 之后的父类名,可以很方便的改变对象的父类。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值