使用 Tag 属性 - 第三部分
DataWindow 列的 Tag 属性的使用
这是本系列文章的第三部分,也是最后一部分,介绍了一种用于 DataWindow 列的 Tag 属性的提案。我最初的想法是提供一种为每列自动设置微帮助的方法。当然,如果您使用 MDI 应用程序,则有一个设置微帮助的函数,但该函数仅在 MDI 中可用。如果您使用任何其他应用程序类型,则无法使用此功能。
即使您确实有一个 MDI,我也发现微帮助不像我希望的那样有用。微帮助总是在框架上,离列很远。用户可能会完全错过它。
为了实现一些可能更有用的功能,我们在工具库中创建了几个对象,它们组合在一起将提供我们所需的功能。您需要这些对象才能重现我们在此处所做的操作。如果您没有从之前的文章中获得它们,您仍然可以在本文的下载源代码中找到它们。
首先,我们必须考虑我们想做什么。我喜欢做的最常见的事情之一是将“pre”(前)和“post”(后)事件关联到 DataWindow 列。我们可以进行设置,以便在列获得焦点之前有一个事件,类似于 PFC 中窗口的 preOpen 和 postOpen 事件。为此,我们需要能够在 Tag 属性中有两个不同的值。一个用于命名 pre-event,另一个用于 post-event。
当然,首先要决定隐喻。我们如何区分 pre-event 和 post-event?我们有一个 Tag,它是一个字符串。我们如何分隔值?
一方面,我们可以使用 ini 文件隐喻,key=value。我们仍然会面临多个值的问题。我们可以这样做
Pre-event=ue_pre_focus;post-event=ue_post_focus
我更喜欢另一种我从某处学到的风格
[pre_event]ue_pre_focus[post_event]ue_post_focus
当列获得焦点时,我们需要扩展我们的 DataWindow 对象,将所有键/值对加载到我们的 key_value 对对象中。
从一个 DataWindow 开始
我们需要的第一件事是一个 DataWindow,它能给我们一些合理的使用对象。我们来做一个员工编辑器 DataWindow。
创建一个具有 freeform 演示风格的新 DataWindow。它需要一个 SQL Select 数据源。选择所有列,然后按姓氏和名字排序。
当然,DataWindow 需要进行格式化。它看起来一点也不好。emp_id 应该是只读的,所以我们将其制作成一个计算字段。
我们需要为部门和经理字段创建下拉列表。它们是 ID,但如果我们制作一个下拉列表 DataWindow,它们可以显示名称。所以我们需要两个新的 DataWindow。我喜欢将它们命名为 dddw_department 和 dddw_employee,因为我可能想在其他地方重用它们。将它们放在自己的 pbl 中是个好主意,这样您就可以始终快速找到它们。我将它们放在我的 tools pbl 中。
两个下拉列表都将是只读的,所以我们删除所有列并添加一个计算字段。员工下拉列表的计算字段具有此表达式
‘(‘ + emp_id + ‘) ‘ + emp_lname + ‘, ‘ + emp_fname
部门的下拉列表 DataWindow 稍微复杂一些,但也不是太难。您需要从部门表中选择部门名称。在部门表中,您会找到一个名为 dept_head_id 的列。使用它连接到员工表并获取部门负责人的姓名(参见图 1)。
请注意,如果您首先选择部门表,然后选择员工表,您的连接将基于 dept_id。您需要更改它。如果您先打开员工表,那么连接将是您想要的。
最后按部门名称排序。然后删除 DataWindow painter 上的所有对象并添加一个计算字段。这是我的表达式
department_dept_name + ‘ (‘ + employee_emp_lname + ‘, ‘ + employee_emp_fname + ‘)'
格式化 DataWindow 后,我们将其放入窗口并检索它。当然,该窗口需要从我们的应用程序打开事件中打开。
我们在 DataWindow 下方添加一个静态文本。我们将用于测试。您的窗口应该看起来像图 2。
终于到了文章的重点
我们真正需要的是一个行为类似于 rowFocusChanging
事件但针对列的事件。我们来创建它。我们需要将正在离开的列和将要进入的列传递给该事件。我们在 u_dw
中完成此操作,并首先添加一个实例变量来保存我们之前所在的列。完成后,这些将是我们的实例变量
U_dw instance variables private string is_selection_mode = "n" private n_cst_dw_row_helper idw_row_helper private u_dw_microhelp io_microhelp private boolean ib_microhelp_registered = FALSE private string is_last_column = "" n_cst_key_value_collection io_key_values
注意:最后一个变量将在本文后面使用。请耐心等待。
我们将使用 is_last_column
来存储我们之前所在的列。正如您所见,它被初始化为空字符串。接下来,我们需要创建一个 itemFocusChanging
事件,就像 rowFocusChanging
一样。它不需要任何代码。它只需要存在并接受两个字符串变量。以下是它的代码
U_dw. itemFocusChanging // ARGUMENTS // string as_old_column // string as_new_column // DESCRIPTION // As_old_column is the column we are coming // from. as_new_column is the column we are going to
现在我们需要从 ItemFocusChanged
事件中调用这个列。这是代码
u_dw.ItemFocusChanged // ARGUMENTS Long row, dwo the column // DESCRIPTION // If there is a tag property set for the dwo and if the microhelp is instantiated // I display that tag // Then we need to call the new itemFocusChanging events passing // the old column and the new one. // 3/26/2011 Rik Brooks // 5/20/2011 Rik Brooks - added the call to the itemFocusChanging IF ib_microhelp_registered then io_microhelp.text = dwo.tag trigger event itemFocuschanging( is_last_column, dwo.name) is_last_column = dwo.name
所以现在我们有了一个事件,它允许我们处理离开列和进入列。这正是我们所需要的。
自动化我们的事件
下一步是向我们的新事件添加代码,该代码会检查两个列中的 Tag。如果旧列中有“post”事件 Tag,则先执行它。然后我们检查新列中是否有 pre-event Tag 并执行它。
此事件有一个小转折。我们不知道 Tag 中可能有多少个命令。可能只有一个,或者两者都有,或者将来我们可能有许多。这时我们需要 key / value 对象。查看 tools pbl,您会找到 n_cst_key_value_collection
。同样,如果您没有 tools.pbl,您可以下载它,或者给我发邮件,我会发给您。
这个对象只有两个函数与我们相关。我们将需要 of_add
和 of_value
。我们从 itemFocusChanging
事件调用 of_add。
当我考虑要做什么时,我意识到我们在创建 key value 对象时错过了一个至关重要的函数。我忘记添加一个函数来清除该对象以便可以重用它。我们来打开该对象并添加 of_clear
函数
n_cst_key_value_collection.of_clear // DESCRIPTION // resets the object so that it holds no values ids_key_value.reset( )
这是我们使用之前提到的神秘实例变量 lo_key_values
的地方。它将保存当前对象的 Tag 中的值。首先,我们必须创建它。我们在 u_dw
的构造函数中执行此操作
Constructor of u_dw // DESCRIPTION - initialize variables io_key_values = create n_cst_key_value_collection
现在在 itemFocusChanging
中,我们添加使这一切正常工作的代码。
U_dw. itemFocusChanging // string as_old_column // string as_new_column // DESCRIPTION // As_old_column is the column we are coming // from. as_new_column is the column we are going to. // It also handles pre and post events for the column if io_key_values.of_count() > 0 then // We have values on the tag of the old column string ls_event, ls_tag ls_event = io_key_values.of_value( "post_event") if len(ls_event) > 0 then triggerevent(ls_event) end if // Post event is done. Now we clear out the key values // and load it with the new column. io_key_values.of_clear() ls_tag = this.describe(as_new_column + ".Tag") if len(ls_tag) > 0 then // We have a tag, load it into our key value object // Format is [key]value int li_left, li_right, li_next_left string ls_key, ls_value li_left = pos(ls_tag, "[") // the first left bracket do while li_left > 0 li_right = pos(ls_tag, "]", li_left) if li_right > 0 then ls_key = mid(ls_tag, li_left + 1, li_right - li_left - 1) li_next_left = pos(ls_tag, "[", li_right)// Now find the next key if li_next_left > 0 then ls_value = mid(ls_tag, li_right + 1, li_next_left - li_right - 1) else ls_value = right(ls_tag, len(ls_tag) - li_right) end if // Finally we can add to our key values io_key_values.of_add(ls_key, ls_value) li_left = li_next_left else // If there is no right bracket then we are done, something // somehow got corrupted. Just forget the whole // thing li_left = -1 end if loop end if // Done. Now let's see if there is a pre event for the new one ls_event = io_key_values.of_value( "pre_event") if len(ls_event) > 0 then triggerevent(ls_event)
几乎完成 基本上我们已经完成了,但我们需要一个测试。回到您的 d_employee
DataWindow。转到 emp_fname
列,并在 Tag 中输入
[pre_event]ue_pre[post_event]ue_post
最后打开 w_main。为 dw_1
添加两个新事件。一个命名为 ue_pre,另一个命名为 ue_post。在每个事件中放置一个消息框。现在运行您的应用程序。当您进入名字字段时,ue_pre
事件将触发。当您离开该列时,ue_post
事件将触发。
显然,您可以拥有任意数量的事件。您可以拥有 ue_pre_name
、ue_prev_city
等。您还可以做得更远。您可以添加其他类型的 Tag 命令。所有命令都将自动进入 key value 对象。您只需在 itemFocusChanging
事件中为它们添加功能。
哦,对了,这让我想起了一件事——我敢打赌,您会发现 itemFocusChanging
事件除了 Tag 值之外还有很多用途。