Oracle Retail(Retek)中实现编辑器的方法总结

在这篇文章中,我想总结的是在开发oracle retailform的时候,怎么实现编辑器,首先我要说明的是我也不知道该怎么称呼这种功能,我姑且就给它随意取个名字叫做编辑器好了,大概的实现效果如下图1所示:

oracle retail中的弹出备注、说明

图1:oracle retail中的编辑器

上图1所示的功能是:当点击红框内的那种图标按钮时,就会弹出一个对话框,对话框中显示的内容来自form中的一个指定的item,也可以编辑对话框中的内容,然后确认保存更改,当然,这种只是对于item可更改的情况而言,对于在只有查看权限情况下,这里只是输出了一个指定item中的内容。

为实现上面的这种功能,我们可以根据下面的步骤来一步步实现(基于fm_templ.fmb模版来做简单化示例开发):

Step 1:基于fm_templ.fmb模版创建一个新form,暂命名为cmx_test.fmb,form的name属性设置为FM_TEST,如下图2所示。

设置form的name属性

图2:设置form的name属性

Step 2:加载OG_EDITOR对象组,我是直接从系统提供的form中将OG_EDITOR对象组拖进来的,读者在操作的时候也可以直接拖过来,然后会发现自动加载了如下图3红色框内的对象,注意,由于截图的时候我没太注意,有个地方忘了圈红框了,图中的程序单元里的P_EDITOR程序包也是自动加载过来的。

加载OG_EDITOR对象组,并自动加载相关的Window、canvas、block等

图3:加载OG_EDITOR对象组,并自动加载相关的Window、canvas、block等

Step 3:上面的第二步基本上已经把实现该功能的核心给介绍了,现在需要做的就是自己建个数据块、窗口、画布等等,然后在基于实现某个功能的基础上调用到本文最开始提到的那个功能,怎么基于fm_templ.fmb模版创建新form以及其修改、设置这里不多说了,下面直接进去第四步,看一个已经设置修改好的form中如何来实现这个功能。

要实现当点击红框内的item时,将绿框内的item_desc的值显示出来

图4:要实现当点击红框内的item时,将绿框内的item_desc的值显示出来

Step 4:参见上图4,要实现当点击红色框内的item时,将绿框内的item_desc的值显示出来。首先,对红框内的item做如下图5所示的设置:

设置按钮item属性

图5:设置按钮item属性

上图5只是列出了核心的部分,最主要的是要设置项类型为按钮,图标文件名为smaltalk,下面还应该设置视觉属性组为TEXT_BUTTON_VAL_OFF,以及该item要显示在哪个canvas上面,不过这个不是这里的重点,就不截图了。

Step 5:设置好了以后,给红色框内的item增加一个when-button-pressed触发器,并且在触发器中增加如下代码:

BEGIN
  -- 对于可编辑和不可编辑做判断后,分两种方式处理。
  IF get_item_property('B_item_master.item_desc',
                       updateable) = 'FALSE' THEN
    p_editor.call_editor('B_item_master.item_desc',
                         'N',
                         'LABL',
                         'DESC',
                         NULL,
                         NULL);
  ELSE
    p_editor.call_editor('B_item_master.item_desc',
                         'Y',
                         'LABL',
                         'DESC',
                         NULL,
                         NULL);
  END IF;
EXCEPTION
  WHEN form_trigger_failure THEN
    RAISE;
  WHEN OTHERS THEN
    emessage(SQLERRM);
    RAISE form_trigger_failure;
END;

上面的这段代码只是用作参考,在具体实现的时候,将其中的B_item_master.item_desc,DESC等都更换成自己需要的,在这里,需要对p_editor.call_editor程序做一个简单的介绍:

p_editor程序包是在之前拖入OG_EDITOR对象组的时候自动加载进来的,并且包里面的方法也都写好了,不用做特别的修改,p_editor包中的call_editor实现代码如下所示:

PROCEDURE call_editor(i_item         IN VARCHAR2, -- 指定用来编辑的项
                      i_editable_ind IN VARCHAR2, -- 指定编辑的模式,Y表示可编辑,N表示不可编辑
                      i_code_type    IN VARCHAR2, -- 表示code_head或code_detail表中的code_type类型
                      i_title_code   IN VARCHAR2, -- 表示code_detail表中的code值
                      i_x_position   IN NUMBER, -- 编辑器的x轴方向位置
                      i_y_position   IN NUMBER) -- 编辑器的y轴方向位置
 IS
  o_error      VARCHAR2(255);
  l_title      code_detail.code_desc%TYPE;
  l_code_type  code_detail.code_type%TYPE;
  l_title_code code_detail.code%TYPE;
  l_x_position NUMBER;
  l_y_position NUMBER;
  l_width      NUMBER;
  l_height     NUMBER;
BEGIN
  -- 这里需要注意下,下面的代码中有个FM_EDIT,这个可以在form_elements和form_elements_langs表中查到相关的注册信息,怎么查询这里不写了,可以在博客中搜索form_elements关键字,我有总结过。
  p_get_labels('FM_EDIT');
  IF i_item IS NULL THEN
    emessage('EDITOR_ITEM'); -- 这里的EDITOR_ITEM提示信息在rtk_errors表中注册过,提示的信息是:货品必须与此编辑器关联。
    RAISE form_trigger_failure;
  ELSIF i_editable_ind NOT IN ('Y',
                               'N') THEN
    emessage('EDITOR_IND'); -- 这里的EDITOR_IND提示信息在rtk_errors表中注册过,提示的信息是:可编辑指示必须与此编辑器关联。
    RAISE form_trigger_failure;
  END IF;
  ---
  -- 下面这段代码是要指定在code_detail中code_type的类型,这里用的是LABL
  IF i_code_type IS NULL THEN
    l_code_type := 'LABL';
  ELSIF i_code_type IS NOT NULL THEN
    l_code_type := i_code_type;
  END IF;
  ---
  -- 下面的这段代码是指定编辑器显示的标题,也是从code_detail中取值,取值逻辑是从code_detail中先匹配code_type,再匹配code。
  IF i_title_code IS NULL THEN
    l_title_code := 'COM';
  ELSIF i_title_code IS NOT NULL THEN
    l_title_code := i_title_code;
  END IF;
  ---
  -- 这里取得x轴位置
  IF i_x_position IS NULL THEN
    ---
    IF :system.event_window IS NOT NULL THEN
      l_x_position := (get_window_property(:system.event_window,
                                           width) - get_window_property('W_EDITOR',
                                                                         width)) / 2;
    ELSE
      l_x_position := 100;
    END IF;
  ELSIF i_x_position IS NOT NULL THEN
    l_x_position := i_x_position;
  END IF;
  ---
  IF l_x_position < 0 THEN
    l_x_position := 0;
  END IF;
  ---
  -- 这里取得y轴位置
  IF i_y_position IS NULL THEN
    ---
    IF :system.event_window IS NOT NULL THEN
      l_y_position := (get_window_property(:system.event_window,
                                           height) - get_window_property('W_EDITOR',
                                                                          height)) / 2;
    ELSE
      l_y_position := 100;
    END IF;
    ---
  ELSIF i_y_position IS NOT NULL THEN
    l_y_position := i_y_position;
  END IF;
  ---
  IF l_y_position < 0 THEN
    l_y_position := 0;
  END IF;
  ---
  -- 这里调用了language_sql包来获取desc描述,其取值结果可以打开language_sql包,然后传递参数test一下,正常情况下,这里l_title的返回值就是编辑器的title。
  IF language_sql.get_code_desc(o_error,
                                l_code_type,
                                l_title_code,
                                l_title) = FALSE THEN
    emessage(o_error);
    RAISE form_trigger_failure;
  END IF;
  ---
  lp_editor_item        := i_item;
  gp_edit_editor_ind    := i_editable_ind;
  lp_call_editor_button := :system.cursor_item;
  copy(name_in(i_item),
       'B_editor.TI_editor');
  lp_edit_length := get_item_property(i_item,
                                      max_length);
  ---
  set_window_property('W_EDITOR',
                      title,
                      l_title);
  set_window_property('W_EDITOR',
                      position,
                      l_x_position,
                      l_y_position);
  ---
  IF i_editable_ind != 'Y' THEN
    rwidget.turn_off('B_editor.TI_editor');
    rwidget.display_off('B_editor.PB_cancel');
    set_item_property('B_editor.PB_OK',
                      position,
                      97,
                      106);
    go_item('B_editor.PB_ok');
  ELSE
    rwidget.turn_on('B_editor.TI_editor');
    rwidget.display_on('B_editor.PB_cancel');
    rwidget.turn_on_cancel_button('B_editor.PB_cancel');
    set_item_property('B_editor.PB_OK',
                      position,
                      64,
                      106);
    go_item('B_editor.TI_editor');
  END IF;
  ---
EXCEPTION
  WHEN form_trigger_failure THEN
    RAISE;
  WHEN OTHERS THEN
    emessage(SQLERRM);
    RAISE form_trigger_failure;
END call_editor;

需要注意的地方,我直接都在上面的代码中加注释了。

Step 6:基本上核心代码就是上面那么多,最终的实现效果如下图6所示:

最终实现效果

图6:最终实现效果

在Step 5中提到了FM_EDIT在form_elements表和form_elements_langs表中的注册信息,下面把注册信息的SQL粘下来用作参考:

INSERT INTO form_elements
  (fm_name, block_name, item_name, item_type, sub_item_name, default_label_prompt, default_access_key, base_ind)
VALUES
  ('FM_EDIT', 'B_EDITOR', 'PB_OK', 'Push Button', 'NONE', 'OK', 'O', 'Y');
INSERT INTO form_elements
  (fm_name, block_name, item_name, item_type, sub_item_name, default_label_prompt, default_access_key, base_ind)
VALUES
  ('FM_EDIT', 'B_EDITOR', 'PB_CANCEL', 'Push Button', 'NONE', 'Cancel', 'C', 'Y');
INSERT INTO form_elements_langs
  (fm_name, block_name, item_name, sub_item_name, lang, lang_label_prompt, lang_access_key, base_ind)
VALUES
  ('FM_EDIT', 'B_EDITOR', 'PB_OK', 'NONE', 1, 'OK', 'O', 'Y');
INSERT INTO form_elements_langs
  (fm_name, block_name, item_name, sub_item_name, lang, lang_label_prompt, lang_access_key, base_ind)
VALUES
  ('FM_EDIT', 'B_EDITOR', 'PB_CANCEL', 'NONE', 1, 'Cancel', 'C', 'Y');
INSERT INTO form_elements_langs
  (fm_name, block_name, item_name, sub_item_name, lang, lang_label_prompt, lang_access_key, base_ind)
VALUES
  ('FM_EDIT', 'B_EDITOR', 'PB_CANCEL', 'NONE', 8, '取消', 'C', 'Y');
INSERT INTO form_elements_langs
  (fm_name, block_name, item_name, sub_item_name, lang, lang_label_prompt, lang_access_key, base_ind)
VALUES
  ('FM_EDIT', 'B_EDITOR', 'PB_OK', 'NONE', 8, '确定', 'O', 'Y');

注意,上面的这段insert语句注册了多语言(简体中文和英文),如果不需要多语言注册的话,可以把lang为8的删掉。如果上面的form在编译的时候报错,说是缺少库文件,那么可以把相应的库文件加载进来。

本文标题:Oracle Retail(Retek)中实现编辑器的方法总结

本文链接:http://yedward.net/?id=159

本文版权归作者所有,欢迎转载,转载请以文字链接的形式注明文章出处。

相关文章