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

DataWindow 的基于服务的架构

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2012年1月20日

CPOL

7分钟阅读

viewsIcon

15009

downloadIcon

136

最小化 DataWindow 所需的内存量

服务对象是在PowerBuilder Foundation Classes(PFC)问世的同时引入PowerBuilder的。和PFC一样,大多数程序员都找到了不使用它们的理由。在本文中,我们将降低这些对象的复杂性,从而可能开启一个高效、易于维护和理解的新世界。

本文将为DataWindow创建一个服务对象。这个对象及其类似对象的想法是最小化DataWindow的占用空间。我们希望最小化DataWindow所需的内存量,从而提供我们能达到的最佳响应速度。

PowerBuilder程序员最常用的功能之一是DataWindow的行选择。您有多少次进入DataWindow控件的Clicked事件并键入类似以下内容的代码?

This.selectRow(0, FALSE) // Turn off all the rows
This.selectRow(row, TRUE) // Turn on the row that was clicked.

我们中的大多数人可能已经写过类似这样的代码几百次了。当我们需要做更复杂的事情,例如需要处理Ctrl+点击和Shift+点击的扩展选择时,情况会变得更糟。当编写带有实例变量anchor row(锚定行)和Clicked事件中数十行代码的Shift+点击功能时,我们开始考虑代码重用性……而代码重用性是面向对象编程的一个关键术语。

我们中的大多数人最终会从标准DataWindow继承我们自己的DataWindow控件。然后,我们将这段代码放入祖先DataWindow中。不久之后,您的u_dw的clicked事件就会变得非常庞大。这可能不是坏事,因为这些用于选择行的代码仅在您的显示样式为表格或网格时使用。在所有其他情况下,您将携带大量不会用到的代码。同样,如果只是DataWindow的行选择,那也许还不算太糟糕,但当你考虑到代码中所有发生这种情况的地方时,你会发现你的应用程序运行得比必需的慢,并且占用的内存比必需的多。

请看图1。您可以看到祖先DataWindow。它有三个可用的服务对象(在此示例中)。假设这是一个表格显示样式。那么就不需要图形辅助对象或树形视图辅助对象。这就是为什么祖先DataWindow和行选择器对象之间存在连接的原因。

Brooks-fig-1.jpg

这种连接是通过调用of_register来处理的。

无论细节如何,我都使用相同的比喻来连接服务对象与它们所服务的对象。服务对象有一个of_register函数,该函数由被服务的对象调用。of_register有一个参数,允许服务对象“记住”它所服务的对象的实例,方法是设置一个实例变量。(哇,这难道不比泥巴还清晰吗?)

以我们的例子来说。让我们创建一个行选择器对象。所以,只需启动PowerBuilder并创建一个自定义类。给它三个实例变量。

private u_dw iuo_dw // object to service
private string is_selection_mode // listbox, normal, toggle, or extended
private long ll_anchor = 0 // used with the extended selection mode

输入完之后,就可以保存您的对象了。我将其命名为n_cst_dw_row_helper。当然,n_cst表示非可视化自定义,但我喜欢添加服务对象所服务的数据类型,以便在pbl中进行排序。在这种情况下,它是DataWindow或dw。

现在让我们看看该对象中的of_register函数。

// n_cst_dw_row_helper.of_register
// ARGUMENTS                    u_dw   adw
// DESCRIPTION
// Registers the argument adw so that this object has a handle back to the serviced object
iuo_dw = adw // The code

这里您可以看到我只有一行代码。我传递了一个u_dw类型的参数(是的,您可以这样做),然后将实例变量设置为该对象。现在,服务对象“知道”了被服务的对象,并且可以通过引用iuo_dw来引用它。

为了使这个图景完整,让我们看看of_register函数是在哪里被调用的。那会在u_dw内部。

首先,我们创建u_dw。这是通过创建一个新的标准类型类来完成的。然后,我们从出现的对话框中选择DataWindow。让我们先看看实例变量。

private string is_selection_mode = "n"
private n_cst_dw_info            idw_info
private n_cst_dw_treeview_helper idw_treeview
private n_cst_dw_graph_helper idw_graph
private n_cst_dw_row_helper idw_row_helper

在这种情况下,我们最感兴趣的是实例变量的最后一行,也就是保存行辅助对象指针的那一行。当然,它还没有被实例化,所以这并不是全部。我们在设置选择模式的函数中实例化了行辅助对象。为什么?因为除非我们设置了选择模式,否则行辅助对象是不需要的——也就是说,选择模式是行辅助对象工作的先决条件。让我们看看u_dw中的of_selection_mode函数。

// public u_dw.of_selection_mode
// ARGUMENTS                    String  as_mode
// RETURN VALUE  String, the old selection mode
// DESCRIPTION      Sets the selection mode. It instantiates the object if needed.
if not isValid(idw_row_helper) then
// Instantiate and register
idw_row_helper = create n_cst_dw_row_helper
idw_row_helper.of_register( this)
end if
return idw_row_helper.of_selection_mode( as_mode)

现在我们开始将这些零散的部件联系起来。我们在辅助对象中创建了一个of_register。然后我们在of_selection_mode函数中调用了该函数。现在,服务对象知道了要服务的对象(n_cst_dw_row_helper知道u_dw),而要服务的对象也知道了服务对象;我们已经建立了这个链接。

在函数中的最后一行,我们调用了服务对象中的of_selection_mode。让我们看看那个函数,看看它做了什么(参见列表1)。(列表1-4可以在此下载。)

of_selection_mode函数所做的就是确保参数有效,设置一个实例变量,并返回旧值。

我们现在快完成了。让我们看看列表中显示的DataWindow的clicked事件(参见列表2)。我们会在这个事件中使用行辅助对象。

第一行非常重要。我们必须始终测试idw_row_helper,或者任何服务对象,是否已被实例化。

一旦我们知道它已经被实例化,我们只需在服务对象中调用of_clicked函数。由于扩展选择模式需要响应Ctrl键和Shift键,我们需要传递它们。这就是我调用keyDown函数的原因。

由于我们在行辅助对象中调用了of_clicked函数,我们应该看看它(参见列表3)。

此函数仅查看当前选择模式(记住,我们设置了该模式来实例化我们的服务对象。基于该模式,它要么直接返回,要么调用以特定方式处理行选择的函数。

最后,让我们看看of_toggle_row、of_extended_row和of_listbox_row,这样我们就解释了所有部分(参见列表4)。

我们已经实现了目标。我们有一个行辅助对象,可以通过几行代码来实现。该对象的实际功能被很好地分段在各个函数中,因此易于查找。为了完善这一点,让我们看看使用我们新对象有多么容易。目标是让应用程序看起来像图2。

Brooks-fig-2_0.jpg

当然,我们要做的第一件事是为我们的应用程序对象编写一个open事件。我创建了一个空窗口,以便在应用程序的open事件中调用打开它。

// Profile EAS Demo DB V115
SQLCA.of_auto_display_message( TRUE)
SQLCA.DBMS = "ODBC"
SQLCA.AutoCommit = TRUE
SQLCA.DBParm = "ConnectString='DSN=EAS Demo DB V115;UID=dba;PWD=sql'"
connect using sqlca ;
open(w_main)

由于您都有示例数据库,所以我总是在示例应用程序中使用它。DataWindow是表格形式的。数据源是sql select,sql语句如下。

SELECT "employee"."emp_id",
"employee"."emp_fname",
"employee"."emp_lname"
FROM "employee"

现在,我们在w_main的表面上放置一个u_dw。我假设您知道如何做到这一点。我将我的控件命名为dw_emps。

现在我们需要获取DataWindow所需的两个显而易见的行代码。我将它们放在我的窗口的post_open事件中(好吧,我继承了窗口,但这超出了本文的范围)。

// w_main::post_open
// DESCRIPTION Populates the employee datawindow
dw_emps.setTransObject(sqlca)
dw_emps.retrieve()

最后,我们需要在右侧放置单选按钮,并在它们周围放置一个组合框。这是每个单选按钮的代码。到目前为止,您应该很清楚它们的作用了。

// w_main.rb_normal::checked
// DESCRIPTION Sets the datawindow selection Mode to normal
dw_emps.of_selection_mode( "normal")
// w_main.rb_extended::checked
// DESCRIPTION Sets the datawindow selection Mode to extended
dw_emps.of_selection_mode( "extended")
// w_main.rb_extended::checked
// DESCRIPTION Sets the datawindow selection Mode to extended
dw_emps.of_selection_mode( "extended")
// w_main.rb_toggle::checked
// DESCRIPTION Sets the datawindow selection Mode to toggle
dw_emps.of_selection_mode( "toggle")

因此,一旦您创建了服务对象,您所要做的就是调用of_selection_mode。该调用会在需要时实例化服务对象,如果不需要则直接使用它。

用一个关闭应用程序的命令按钮完成您的应用程序,这样您就已经演练了您的应用程序。

© . All rights reserved.