65.9K
CodeProject 正在变化。 阅读更多。
Home

登上等级制度的顶端

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2011 年 10 月 14 日

CPOL

6分钟阅读

viewsIcon

10818

啄序与 PowerBuilder 有什么关系?在 PowerScript 编码中,啄序何时重要?继续阅读以了解其联系!

"鸡群有一个明确的等级制度,称为“啄序”。处于啄序顶端的鸡可以随心所欲地做自己想做的事情,通过“欺负”其他鸡来实现,如果它们不服从,就会受到短暂而尖锐的啄击,这样它就可以去自己想去的地方,或者先吃到食物和喝到水。鸡群天生就有啄序,以确保它们和谐相处。当有食物时,就不会发生争斗。大家都能和平相处。

处于啄序顶端的鸡可以优先获得水源、食物、最好的栖息地等等。处于啄序底端的鸡在鸡群中拥有的“权利”最少,通常是最后一个吃到食物,并且会“绕着”分散给它们的食物吃,伺机 grab 一口。她(有时是雄性)对食物和其他资源的获取拥有最后的机会。" 完整的故事和视频请查看 http://poultrykeeper.com/chickens/frequently-asked-questions/what-is-the-pecking-order.html

PowerBuilder 场景

您的应用程序有一个窗口,其中包含自定义可视化用户对象 (CVUO),这些对象在其构造函数事件中需要系统服务。显然,在调用 CVUO 构造函数之前,服务必须已经驻留并处于活动状态。使用全局变量(函数或 NVO 引用)是一种方法,但您希望以面向服务的面向对象的方式编写解决方案。作为一个面向对象的爱好者,您不希望服务具有全局范围。您更愿意将 NVO 定义为窗口服务。您在窗口上声明一个自定义类用户对象 (NVO),并在其 Open 事件中实例化它。窗口定义一个 NVO 实例变量,并在其 Open 事件中创建它。CCUO 在其构造函数事件中通过窗口调用 NVO 服务。图 1 显示了系统树中的代码对象。图 2 说明了场景。

f1_0.png

图 1:代码对象

f2_0.png

图 2:窗口中的 CVUO 在构造函数中调用服务

问题在于,NVO 的创建时间晚于 CCUO。在运行时,由于 CVUO 控件的构造函数在服务实例化之前被调用,因此会抛出 Null Object 错误。图 3 显示了窗口事件序列。请注意,排在第 3 位(NVO 构造函数)排在第 1 位(CCUO 构造函数)之后。换句话说,NVO 在啄序中排名靠后。我们如何将 NVO 移到第 1 位?毕竟,Open 事件总是在所有控件创建之后发生的?我将向您展示三种可能的解决方案。您可以选择最适合您口味的一种。

f3_0.png

图 3:NVO 在啄序中排名靠后

解决方案 1:延迟 CCUO 构造函数代码

我将第一个解决方案称为“经典”,因为它依赖于一种自最早版本以来就存在的技术。该解决方案依赖于 Post 与 Trigger 事件调用的时序。每个 PowerBuilder 程序员都曾在 Window Open 事件级联中见过这种技术。您将一个通常称为 ue_postconstructor 的事件添加到 CCUO,在构造函数中对其进行 this.PostEvent( ) 调用,并将时间敏感的代码从构造函数移动到 ue_postconstructor。正如您在图 4 中看到的,问题得到了解决,因为 ue_PostConstructor 在 NVO 驻留之后被调用。

f4_0.png

图 4:CCUO 代码移至 Post Constructor 后的序列

现在看起来 NVO 是 #1,但实际上并非如此。它之所以在那里,是因为我们失去了记录 CCUO 构造函数(仍然是 #1)的能力,并且在创建日志服务后,我们记录了 Window Open(实际上是 #2)。所以服务实际上仍然是 #3。它只是假装排在了列表的顶端。问题仍然存在:我们如何才能真正将 NVO 移到 #1 位置?在接下来的部分中,我将向您展示两种方法来升级 NVO 实例化。

解决方案 2:自动实例化 NVO

在此方法中,您将在属性表中将 NVO 标记为 AutoInstantiated。这意味着变量声明就是实例化。图 5 显示了设计时 AutoInstantiate 设计符。

f5.png

图 5:AutoInstantiate 设计符

此外,您必须从 Open 事件中删除现在非法的 CREATE 语句。由于实例变量在控件实例化之前分配,因此 NVO 引用被移到 #1。图 6 显示了我们的 NVO 处于顶层位置。

f6_0.png

图 6:NVO 是 #1

但是,需要谨慎:自动实例化的 NVO 的行为类似于结构。也就是说,赋值语句会传递 NVO 的副本,而不是指向原始对象的指针。如果您的 NVO 维护内部状态,这将是一个问题。

解决方案 3:让 Painter 定义 NVO

窗口 Painter 有一个鲜为人知的视图,称为 Non-Visual Object List。如您在图 7 中所见,在默认布局中,它位于包含 Properties View 的同一个文件夹底部的选项卡上。

f7_0.png

图 7:非可视化对象列表

它列出了您在 Painter 中放置在布局表面的非可视化用户对象。您可以通过从 System Tree 拖放非可视化控件到 Layout,或者使用菜单项来完成此操作。图 8 显示了 Window Painter 中的 Insert Object 菜单。

f8.png

图 8:放置 NVO 到布局

当您放置 NVO 时,Painter 会像任何可视化控件一样为其提供一个默认名称 - 类名前缀后跟一个数字后缀。您可以使用属性表使名称遵循您的标准命名约定。图 9 显示了定义 NVO 后的视图。请注意,只能通过这种方式定义非自动实例化的 NVO。

f9_0.png

图 9:非可视化对象列表

Painter 是一个特权角色。它可以编写开发人员域之外的框架源代码。在我们的例子中,Painter 在 Type Declaration 部分定义 NVO,并在 CREATE 事件中对其进行实例化。这意味着 NVO 在实例化过程中更早地被实例化。图 10 显示了 Painter 生成的代码的一部分。

f10_0.png

图 10:生成的源代码

除了在啄序中上升到第一位之外,NVO 还通过这种方法获得了另外两个奖励功能;首先,NVO 的行为类似于 NVO。赋值语句会分配内存中单个对象的地址;状态会保留。其次,与可视化控件一样,NVO 成为定义在窗口内的内部控件。正如您在图 11 中所看到的,您可以在窗口 Painter 中为其编写额外的事件处理代码。这将来可能会有用!

f11_0.png

图 11:NVO 在窗口脚本编辑器中

还有一个谜团仍未解决。仔细阅读 CREATE 代码可以看到 NVO 是在 CCVOS 之后创建的。按理说,CCUO 构造函数中的 NVO 调用应该失败。但它们却能正常工作!!?显然,运行时内部存在一些障眼法。

结论

PowerBuilder,就像生活中的几乎所有事物一样,提供了合理的表面体验,但同时提供了您可以遵循和使用的线索和工具来超越群体。只要有追求更好解决方案的愿望和坚持到底的毅力,您就能找到编写更好代码的方法,从而在啄序中名列前茅。

© . All rights reserved.