服务器 频道

Oracle Form Builder中使用树的心得

  二、生成树的方式
  
  树控件一般单独放在一个控制块中(注:不能放在数据块中),在画布(CANVAS)上放置树很容易,并且,如无必要,树的属性也不需要设置。
  
  生成树的方式有几种:
  
  l 运行前通过设置记录组或数据查询属性来生成
  
  l 通过ADD_TREE_DATA触发子来实现
  
  l 运行态,通过ADD_TREE_NODE等触发子来实现
  
  l 运行态,通过添加或删除记录组的数据元素来实现
  
  分析:
  
  一、 对树直接操作

  
  描述:Find_Tree_Node找到指定节点,Add_Tree_Node来添加其下级节点。
  
  缺点:编程较为复杂,操作不灵活,而且易出错。
  
  优点:可以对添加节点等过程进行控制,实现一些特殊要求。
  
  例子:
  
  --dept_cur为取单位的CURSOR,emp_cur为取雇员的CURSOR
  
  htree := Find_Item(''tree_view.tree_emp'');
  
  open dept_cur;
  
  loop
  
  fetch dept_cur into aa;
  
  exit when dept_cur%notfound;
  
  del_node := Ftree.Find_Tree_Node ( htree,aa.kjmc, Ftree.FIND_NEXT, Ftree.NODE_LABEL, Ftree.ROOT_NODE, Ftree.ROOT_NODE);
  
  -- 删除单位节点及其子节点
  
  IF NOT Ftree.ID_NULL(del_node) then
  
  Ftree.Delete_Tree_Node(htree, del_node);
  
  END IF;
  
  end loop;
  
  close dept_cur;
  
  -- 根据用CURSOR取得的单位生成树的第一层节点
  
  open dept_cur;
  
  loop
  
  fetch dept_cur into aa;
  
  exit when dept_cur%notfound;
  
  new_node := Ftree.Add_Tree_Node(htree, Ftree.ROOT_NODE, Ftree.parent_OFFSET, Ftree.LAST_CHILD, Ftree.EXPANDED_NODE, aa.dname, '''', aa.deptno);
  
  end loop;
  
  close dept_cur;
  
  --根据雇员CURSOR生成树的下层节点
  
  open emp_cur;
  
  loop
  
  fetch emp_cur into bb;
  
  exit when emp_cur%notfound;
  
  find_node := Ftree.Find_Tree_Node(htree, bb.kjbh, Ftree.FIND_NEXT,
  
  Ftree.NODE_value, Ftree.ROOT_node, Ftree.ROOT_NODE);
  
  new_node := Ftree.Add_Tree_Node(htree, find_node, Ftree.parent_OFFSET, Ftree.LAST_CHILD, Ftree.EXPANDED_NODE, bb.ename, '''', bb.empno);
  
  end loop;
  
  close emp_cur;
  
  -- 得到树的根节点
  
  ss := Ftree.get_tree_property(htree,FTREE.NODE_COUNT);
  
  -- 循环,直到树的所有节点都展开
  
  for j in 1..ss LOOP
  
  exp_node := Ftree.Find_Tree_Node(htree, '''');
  
  state := Ftree.Get_Tree_Node_Property(htree, j, Ftree.NODE_STATE);
  
  IF state = Ftree.COLLAPSED_NODE THEN
  
  Ftree.Set_Tree_Node_Property(htree, j, Ftree.NODE_STATE, Ftree.EXPANDED_NODE);
  
  END IF;
  
  END LOOP;
  
  二、 动态记录组
  
  层次树所使用记录组的数据格式:
  
  + — Car
  
  |
  
  - — Airplane
  
  | — Boeing
  
  | — Boeing
  
  
  初始状态
  层数
  显示文本
  图标
  值
  
  -1(收缩节点)
  1
  ‘Car’
  ''''
  ‘car’
  
  0(叶节点)
  2
  ''Honda''
  ''''
  ''civic''
  
  1(展开节点)
  1
  ''Airplane''
  ''''
  ''plane''
  
  0
  2
  ''Boeing''
  ''''
  ''747''
  
  0
  2
  ''Boeing''
  ''''
  ''757''
  
  生成记录组的方式又分为两种。
  
  1、 从查询生成记录组
  
  描述:利用树的查询语句(connect by…prior…start with…)生成记录组,设置树的属性来生成。
  
  优点:编程简单,方便。
  
  缺点:只适用于可以构造出树状查询语句的情况下。
  
  例子:
  
  v_ignore number;
  
  rg_emps recordgroup;
  
  begin
  
  rg_emps := find_group(''EMPS'');
  
  --如果非空,则清空数据
  
  if not id_null(rg_emps) then
  
  delete_group(rg_emps);
  
  end if;
  
  --构造记录组
  
  rg_emps := create_group_from_query(''EMPS'',
  
  ''select 1, level, ename, NULL, to_char(empno) '' ||
  
  ''from emp '' ||
  
  ''connect by prior empno = mgr '' ||
  
  ''start with job = ''''PRESIDENT'''''');
  
  v_ignore := populate_group(rg_emps);
  
  ftree.set_tree_property(''tree_view.tree_emp'', ftree.record_group, rg_emps);
  
  end;
  
  2、 用行列数据直接构造记录组
  
  描述:记录组一般为行列结构,以循环方式直接向记录组中添加单元数据。
  
  优点:可直接控制记录组的样式。
  
  缺点:对多层结构,编程也较为复杂。
  
  例子:
  
  --单位CURSOR
  
  cursor cursor_dept is
  
  select dname, deptno from dept order by dname;
  
  --雇员CURSOR
  
  cursor cursor_emp(p_dno number) is
  
  select ename, empno from emp where deptno = p_dno order by ename;
  
  v_i number;
  
  v_ignore number;
  
  rg_emps recordgroup;
  
  rg_depts recordgroup;
  
  v_init_state groupcolumn;
  
  v_level groupcolumn;
  
  v_label groupcolumn;
  
  v_icon groupcolumn;
  
  v_value groupcolumn;
  
  begin
  
  rg_depts := find_group(''DEPTS'');
  
  --如有数据,则清空记录组
  
  if not id_null(rg_depts) then
  
  delete_group(rg_depts);
  
  end if;
  
  rg_depts := create_group(''DEPTS'');
  
  --这里自定义你需要的记录组中列的数据类型和长度
  
  --初始状态(指展开、收缩还是叶节点)
  
  v_init_state := add_group_column(rg_depts, ''init_state'', number_column);
  
  --所在层数
  
  v_level := add_group_column(rg_depts, ''level'', number_column);
  
  --显示文本
  
  v_label := add_group_column(rg_depts, ''label'', char_column, 40);
  
  --图标
  
  v_icon := add_group_column(rg_depts, ''icon'', char_column, 20);
  
  --值
  
  v_value := add_group_column(rg_depts, ''value'', char_column, 5);
  
  v_i := 1;
  
  for deptrec in cursor_dept loop
  
  add_group_row(rg_depts, v_i);
  
  set_group_number_cell(v_init_state, v_i, 1);
  
  set_group_number_cell(v_level , v_i, 1);
  
  set_group_char_cell (v_label , v_i, deptrec.dname);
  
  set_group_char_cell (v_icon , v_i, NULL);
  
  set_group_char_cell (v_value , v_i, to_char(deptrec.deptno));
  
  v_i := v_i + 1;
  
  for emprec in cursor_emp(deptrec.deptno) loop
  
  add_group_row(rg_depts, v_i);
  
  set_group_number_cell(v_init_state, v_i, 1);
  
  set_group_number_cell(v_level , v_i, 2);
  
  set_group_char_cell (v_label , v_i, emprec.ename);
  
  set_group_char_cell (v_icon , v_i, NULL);
  
  set_group_char_cell (v_value , v_i, to_char(emprec.empno));
  
  v_i := v_i + 1;
  
  end loop;
  
  end loop;
  
  ftree.set_tree_property(''tree_view.tree_org'', ftree.record_group, rg_depts);
  
  end;
  
  结论:进行数据库设计时尽量把父子结构放在一张表,这样,使用查询生成记录组再生成树的方式最简单实用。如果不能实现,那么直接构造记录组也可生成树。如无特殊要求,一般不采取对树直接操作的方式。
  
  附注:作者一般将生成树的程序放在Form Builder的“程序单元”中,在需要的地方调用来实时刷新树。
  
  参考:Developer 6.0自带的PL/SQL程序库:navigate.pll
  
  三、遗留问题
  
  由于developer简化了树的设计,那么一些对树的转移、拷贝等操作就不太容易实现。这个课题还需要继续研究。
0
相关文章