Совершенствование приложений Oracle Forms

Элемент дерево (Tree view)

Разбить на страницы
Показывать лекцию целиком

Элемент Tree View является специфичным не только потому, что требует особых условий и настройки свойств, а еще и потому, что для управления этим элементом в Oracle Forms создан специальный встроенный пакет FTREE. Элемент дерево является очень функциональным, так как позволяет скоординировать и компактно отобразить большой набор данных, разбивая его на логические единицы - узлы. Вы можете заполнять деревья статически и динамически данными из таблиц. В дереве вы можете реализовать отношение Мастер-Деталь, выбирая в качестве родительского узла запись таблицы Мастер, а в качестве дочернего - запись из таблицы Деталь. Вы также можете использовать дерево как навигатор вашего приложения, в котором перечислены все блоки и элементы. Пакет FTREE содержит довольно небольшой объем процедур и функций, которые перечислены ниже:

  • ADD_TREE_DATA ;
  • ADD_TREE_NODE ;
  • DELETE_TREE_NODE ;
  • FIND_TREE_NODE ;
  • POPULATE_GROUP_FROM_TREE ;
  • POPULATE_TREE ;
  • SET_TREE NODE_PROPERTY.
  • Создание Tree View

    Tree View представляет собой прямоугольную область, в которой отображается иерархическое дерево. Для того чтобы создать дерево, выполните следующие действия:

  • Создайте новую форму и сохраните ее как TREE.
  • Находясь в навигаторе объектов, создайте два небазовых блока. Первый блок назовите " TREE ", а второй " CONTR ".
  • Находясь в редакторе разметки, создайте одну канву. Разместите на канве элемент Tree View и две кнопки.
  • Установите для элемента TREE VIEW блок TREE, а все остальные элементы ассоциируйте с блоком " CONTR ".
  • В этом примере мы создали дополнительный управляющий блок данных "CONTR" для последующего использования в примерах.

    Прежде чем построить дерево, рассмотрим основные методы пакета FTREE, которые нам для этого понадобятся.

    Функция ADD_TREE_NODE

    ADD_TREE_NODE (item_id [item_id] ITEM, node NODE, 
          offset_ type NUMBER, offset NUMBER, state NUMBER, 
         label VARCHAR2, icon VARCHAR2, value VARCHAR2) 
    RETURN FTREE.NODE

    - добавляет новый элемент в дерево.

    Метод Параметр Тип Значение
    FUNCTION ADD_TREE_NODE (параметры) RETURN NODE itemname [idname] VARCHAR2 [FORMS4C.ITEM] Определяет имя элемента или его идентификатор
    node FTREE.NODE Определяет вершину дерева
    offsettype NUMBER Определяет тип сдвига для вершины, возможные значения: PARENT_OFFSET, SIBLING_OFFSET
    offset NUMBER Определяет позицию новой вершины: если это PARENT_OFFSET, то позиция 1-n,, или LAST_CHILD. Если тип сдвига SIBLING_OFFSET, то позицией сдвига может быть NEXT_NODE или PREVIOUS_NODE
    state NUMBER Определяет состояние вершины: COLLAPSED_NODE, EXPANDED_NODE, LEAF_NODE
    label VARCHAR2 Отображаемый текст для вершины
    icon VARCHAR2 Имя файла иконки для вершины
    value VARCHAR2 Значение, которое содержит вершина
    Примечание:элемент дерево всегда должен размещаться в отдельном блоке и быть в нем единственным элементом. В предыдущем примере для того чтобы разместить кнопки, нам пришлось создать второй блок, так как блок, содержащий элемент Tree View, не может содержать других элементов. Если вы все же разместите еще один элемент в блоке "TREE", то получите ошибку "FRM-32089 - Деревья должны размещаться в однозаписных блоках с одним элементом".

    Следующий пример описывает процесс добавления нового элемента в существующее дерево.

    DECLARE
     Itree ITEM;
     top_node Ftree.Node;
     new_node Ftree.Node;
     i_value VARCHAR2(30);
    BEGIN
     Itree := Find_Item('tree_block.tree_item ');
     new_node := Ftree.Add_Tree_Node(Itree, Ftree.ROOT_NODE,
       Ftree.PARENT_OFFSET, Ftree.LAST_CHILD,
       Ftree.EXPANDED_NODE, i_value, NULL, i_value);
    END;

    Процедура DELETE_TREE_NODE

    DELETE_TREE_NODE (item_name [item_id] VARCHAR2, node FTREE.NODE) - эта процедура выполняет действие, обратное ADD_ TREE_NODE, то есть удаляет элемент дерева.

    Метод Параметр Тип Значение
    PROCEDURE DELETE_TREE_NODE(параметры) itemname [idname] VARCHAR2 [FORMS4C.ITEM] Определяет имя элемента или его идентификатор
    node FTREE.NODE Определяет вершину дерева, которую необходимо удалить

    Следующий пример описывает процесс удаления вершины и всех ее детей.

    DECLARE
     Itree item := find_item('tree_block.tree_item ');
     del_node Ftree.Node;
     i_value VARCHAR2(30);
    BEGIN
     del_node := Ftree.Find_Tree_Node(Itree, i_value,
      Ftree.FIND_NEXT, Ftree.NODE_LABEL,
      Ftree.ROOT_NODE, Ftree.ROOT_NODE);
     IF NOT Ftree.ID_NULL(del_node) then 
      Ftree.Delete_Tree_Node(Itree, del_node); 
     END IF; 
    END;

    Функция FTREE.GET_TREE_NODE_PARENT

    FTREE.GET_TREE_NODE_PARENT (item_name [item_id] VARCHAR2, node FTREE.NODE) - возвращает родителя указанной вершины дерева.

    Метод Параметр Тип Значение
    FUNCTION DELETE_TREE_NODE (параметры) RETURN NODE itemname [idname] VARCHAR2 [FORMS4C.ITEM] Определяет имя элемента или его идентификатор
    node FTREE.NODE Вершина дерева, для которой отыскивается родитель

    Следующий пример описывает процесс получения родителя указанного элемента.

    DECLARE
     Itree item := find_item('tree_block.tree_item ');
     par_node FTREE.NODE;
    BEGIN
     par_node := Ftree.Get_Tree_Node_Parent(Itree,
       :SYSTEM.TRIGGER_NODE);
     ...
    END;

    Функция FTREE.GET_TREE_NODE_PROPERTY

    FTREE.GET_TREE_NODE_PROPERTY (item_name [item_id] VARCHAR2, node NODE, property NUMBER) RETURN VARCHAR2 - возвращает значение свойства указанной вершины дерева.

    Метод Параметр Тип Значение
    FUNCTION GET_TREE_NODE_PROPERTY (параметры) RETURN VARCHAR2 itemname [idname] VARCHAR2 [FORMS4C.ITEM] Определяет имя элемента или его идентификатор
    node FTREE.NODE Вершина дерева, для которой отыскивается родитель
    property NUMBER Возвращает значение одного из перечисленных свойств: NODE_STATE, NODE_DEPTH, NODE_LABEL, NODE_ICON, NODE_VALUE

    Следующий пример проверяет состояние указанной вершины, и если она не раскрыта, то есть NODE_STATE установлено в COLLAPSED_ NODE, то вершина автоматически раскрывается, то есть NODE_STATE устанавливается в EXPANDED_NODE.

    DECLARE
     Itree item := find_item('tree_block.tree_item ');
    BEGIN
     IF Ftree.Get_Tree_Node_Property(Itree,
       :SYSTEM.TRIGGER_NODE, Ftree.NODE_STATE)=Ftree.COLLAPSED_NODE
     THEN 
      ftree.set_tree_node_property(Itree, 
        :SYSTEM.TRIGGER_NODE, ftree. node_state, ftree.expanded_node); 
     END IF; 
    END;

    Используйте функцию FTREE.GET_TREE_NODE_PROPERTY для получения значения вершины.

    DECLARE
     Itree item := find_item('tree_block.tree_item ');
    BEGIN
     Ftree.Get_Tree_Node_Property(Itree, :SYSTEM.TRIGGER_NODE, 
       Ftree.NODE_VALUE);
     ...
    END;

    Функция FTREE.GET_TREE_PROPERTY

    FTREE.GET_TREE_PROPERTY (item_name [item_id] VARCHAR2, property NUMBER) RETURN VARCHAR2 - возвращает значение свойства указанного элемента дерева.

    Метод Параметр Тип Значение
    FUNCTION GET_TREE_PROPERTY (параметры) RETURN VARCHAR2 itemname [idname] VARCHAR2 [FORMS4C.ITEM] Определяет имя элемента или его идентификатор
    property NUMBER Возвращает значение одного из перечисленных свойств: DATASOURCE, RECORD_GROUP, SET_TREE_PROPERTY, QUERY_TEXT, NODE_COUNT, SELECTION_COUNT, ALLOW_EMPTY_BRANCHES, ALLOW_MULTI-SELECT

    Следующий пример описывает процесс получения количества вершин указанного дерева.

    DECLARE
     Itree item := find_item('tree_block.tree_item ');
     node_cnt NUMBER;
    BEGIN
     node_cnt := Ftree.Get_Tree_Property(Itree,
     Ftree.NODE_COUNT);
     Message('Количество вершин дерева: '||node_cnt);
    END;

    Функция FTREE.GET_TREE_SELECTION

    GET_TREE_SELECTION (item_name [item_id] VARCHAR2, selection NUMBER) RETURN Ftree.NODE - возвращает выделенную вершину дерева.

    Метод Параметр Тип Значение
    FUNCTION GET_TREE_SELECTION (параметры) RETURN VARCHAR2 itemname [idname] VARCHAR2 [FORMS4C.ITEM] Определяет имя элемента или его идентификатор
    selection NUMBER Индекс выделенной вершины дерева

    Следующий пример описывает процесс получения выделенных элементов указанного дерева. Все элементы, помеченные как выделенные, будут удалены, причем удалять элементы нужно в обратном порядке, как показано в примере.

    DECLARE
     Itree item := find_item('tree_block.tree_item ');
     Select_cnt NUMBER;
     del_node FTREE.NODE;
    BEGIN
     Select_cnt:= Ftree.Get_Tree_Property(Itree,
     Ftree.SELECTION_COUNT);
     FOR i IN REVERSE 1..select_cnt LOOP
      del_node := Ftree.Get_Tree_Selection(Itree, i);
      Ftree.Delete_Tree_Node(Itree, del_node);
     END LOOP;
    END;

    Процедура FTREE.SET_TREE_NODE_PROPERTY

    SET_TREE_NODE_PROPERTY (item_name [item_id] VARCHAR2 [FORMS4C.ITEM], node FTREE.NODE, property NUMBER, value NUMBER [VARCHAR2]) - устанавливает свойства элемента дерева.

    Метод Параметр Тип Значение
    PROCEDURE SET_TREE_NODE_PROPERTY (параметры) RETURN VARCHAR2 item_name VARCHAR2 [id_name] [FORMS4C.ITEM] Определяет имя элемента или его идентификатор
    node FTREE.NODE Вершина дерева, для которой устанавливается свойство
    property NUMBER Устанавли вает одно из перечисленных свойств равным value: NODE_STATE, NODE_LABEL, NODE_ICON, NODE_VALUE
    value NUMBER [VARCHAR2] Значение, устанавливаемое для заданного свойства

    Следующий пример описывает процесс поиска корневого узла и его развертывания.

    DECLARE
     Itree item := find_item('tree_block.tree_item ');
     branch_node Ftree.NODE;
     i_value varchar2(30);
    begin
     select_node := Ftree.Find_Tree_Node(Itree, i_value,
       Ftree.FIND_NEXT, Ftree.NODE_VALUE,
       Ftree.ROOT_NODE, Ftree.ROOT_NODE); 
     ftree.set_tree_node_property(Itree, select_node, 
       ftree.node_state, ftree.expanded_node); 
    END;

    С помощью процедуры SET_TREE_NODE_PROPERTY вы можете менять иконку узла в зависимости от какого-либо условия, как показано в листинге 3.8.

    DECLARE
     Itree item := find_item('tree_block.tree_item ');
    BEGIN
     IF Ftree.Get_Tree_Node_Property(Itree,
      :SYSTEM.TRIGGER_NODE, Ftree.NODE_STATE)=Ftree.COLLAPSED_NODE
     THEN Ftree.Set_Tree_Node_Property(Itree, :SYSTEM.TRIGGER_NODE, Ftree.NODE_ICON, 'Close'); 
     ELSIF 
      Ftree.Get_Tree_Node_Property(Itree, :SYSTEM.TRIGGER_NODE, 
            Ftree.NODE_STATE)= Ftree.EXPANDED_NODE
     THEN 
      Ftree.Set_Tree_Node_Property(Itree, :SYSTEM.TRIGGER_NODE, 
        Ftree.NODE_ICON, 'Open'); 
     END IF; 
    END;

    Процедура SET_TREE_PROPERTY

    SET_TREE_PROPERTY (item_name [item_id] VARCHAR2 [FORMS4C.ITEM], property NUMBER, value NUMBER [VARCHAR2, RECORDGROUP]) - устанавливает значение указанного свойства дерева.

    Метод Параметр Тип Значение
    PROCEDURE SET_TREE_PROPERTY (параметры) itemname [idname] VARCHAR2 [FORMS4C.ITEM] Определяет имя элемента или его идентификатор
    property NUMBER Устанавливает одно из перечисленных свойств равным value: RECORD_GROUP, QUERY_TEXT, ALLOW_EMPTY_BRANCHES
    value NUMBER[VARCHAR2,RECORDGROUP] Значение, устанавливаемое для заданного свойства. Для ALLOW_EMPTY_BRANCHES это всегда PROPERTY_TRUE или PROPERTY_FALSE

    В следующем примере разрешается наличие в дереве пустых узлов, то есть элементов, не содержащих детей.

    DECLARE
     Itree item := find_item('tree_block.tree_item ');
    BEGIN
     Ftree.Set_Tree_Property(Itree, Ftree.ALLOW_EMPTY_BRANCHES,
      property_true);
    END;

    Процедура SET_TREE_SELECTION

    SET_TREE_SELECTION item_name [item_id] VARCHAR2 [FORMS4C. ITEM], node NODE, selection_type NUMBER) - устанавливает или сбрасывает выделение указанной вершины.

    Метод Параметр Тип Значение
    PROCEDURE SET_TREE_SELECTION (параметры) itemname [idname] VARCHAR2 [FORMS4C.ITEM] Определяет имя элемента или его идентификатор
    node NUMBER Вершина дерева, для которой устанавливается свойство
    selectiontype NUMBER[VARCHAR2,RECORDGROUP] Определяет тип выделения: SELECT_ON, SELECT_OFF, SELECT_TOGGLE

    Следующий пример описывает процесс поиска корневого узла и его выделение.

    DECLARE
     Itree item := find_item('tree_block.tree_item ');
     select_node Ftree.NODE;
     i_value VARCHAR2(30);
    BEGIN
     select_node:= Ftree.Find_Tree_Node(Itree, i_value,
       Ftree.FIND_NEXT, Ftree.NODE_VALUE,
       Ftree.ROOT_NODE, Ftree.ROOT_NODE); 
     Ftree.Get_Tree_Property(Itree, select_node, ftree.select_on); 
    END;

    Теперь, когда мы рассмотрели все основные процедуры и функции для работы с деревом, можно приступить к его построению. Для начала выполним простой пример, который описывает создание корневого и дочернего узла, причем для построения дерева мы будем использовать шаблон, созданный в предыдущем примере.

  • Установите для кнопки метку "Добавить родительский узел" и создайте для нее событие WHEN-BUTTON-PRESSED. В теле триггера напишите и скомпилируйте строки, которые приведены ниже.
    WHEN-BUTTON-PRESSED
    DECLARE
     r_Node Ftree.Node;
     c_Node Ftree.Node;
    BEGIN
     r_Node:=Ftree.Add_Tree_Node('TREE.TREE',
     Ftree.ROOT_NODE,
     Ftree.PARENT_OFFSET,
     Ftree.LAST_CHILD,
     Ftree.EXPANDED_NODE, 'Главный' , NULL, '1');
    END;
  • Установите для второй кнопки метку "Добавить дочернюю ветку " и создайте для нее событие WHEN-BUTTON-PRESSED. В теле триггера напишите и скомпилируйте строки, которые приведены ниже.
    WHEN-BUTTON-PRESSED
    DECLARE
     h_Node Ftree.Node;
     l_Node Ftree.Node;
    begin
     h_Node:=Ftree.Add_Tree_Node(' TREE.TREE ',
     Ftree.ROOT_NODE,
     Ftree.PARENT_OFFSET,
     Ftree.LAST_CHILD,
     Ftree.EXPANDED_NODE, 'Дочерний' , NULL, '1');
     l_node:=Ftree.Add_Tree_Node('TREE.TREE', h_node, Ftree.Parent_offset,
     ftree.NEXT_NODE,
     Ftree.LEAF_NODE,
     'Дочерний', NULL, '2'); 
    end;
  • Результат работы программы показан на рис. 1. Далее приведен пример с заполнением дерева моделью Мастер-Деталь.

  • Для создания блоков COUNTRY и CITY выполните скрипт, приведенный в листинге 3.12.
    SQL: CREATE TABLE COUNTRY
    (PRkey number PRIMARY KEY, cntr varchar2(100)) /
    SQL: CREATE TABLE CITY (FKkey number, town varchar2(100)) /
    -- вставка значений в таблицу COUNTRY
    SQL: INSERT INTO COUNTRY VALUES (1,'Украина'); 
      SQL: INSERT INTO COUNTRY VALUES (2,'Россия');
        SQL: INSERT INTO COUNTRY VALUES (3,'Германия');
    -- вставка значений в таблицу CITY
    SQL: INSERT INTO CITY VALUES  (1,'Киев');
    SQL: INSERT INTO CITY VALUES  (1,'Львов');
    SQL: INSERT INTO CITY VALUES  (1,'Мариуполь');
    SQL: INSERT INTO CITY VALUES  (2,'Москва');
    SQL: INSERT INTO CITY VALUES  (2,'Санкт-Петербург');
    SQL: INSERT INTO CITY VALUES  (2,'Калининград');
    SQL: INSERT INTO CITY VALUES  (3,'Берлин');
    SQL: INSERT INTO CITY VALUES  (3,'Франкфурт');
    SQL: INSERT INTO CITY VALUES  (3,'Магдебург');
  • Сохраните модуль как relation_tree.
  • Создайте два блока COUNTRY и CITY и свяжите их между собой, установив JOIN CONDITION равным COUNTRY.PRKEY=CITY. FKKEY.
  • Находясь в навигаторе объектов, создайте небазовый блок и назовите его " TREE ".
  • Находясь в редакторе разметки, создайте одну канву. Разместите на канве элемент Tree View и назовите его TREE.
  • Создайте триггер WHEN-NEW-FORM-INSTANCE и напишите в нем нижеприведенный код.
  • WHEN-NEW-FORM-INSTANCE
    DECLARE
     z varchar2(100);
     x number;
     h_Node Ftree.Node;
     l_Node Ftree.Node;
     cursor c1 is select * from country;
     cursor a1 is select * from city;
     c2 c1%rowtype;
     a2 a1%rowtype;
    begin
     open c1;
     for i in (select * from country) loop 
     begin
      :parameter.param:=:parameter.param+1; 
      h_Node:=Ftree.Add_Tree_Node('TREE.TREE', ftree.ROOT_NODE, 
          Ftree.PARENT_OFFSET, Ftree.LAST_CHILD, Ftree.EXPANDED_NODE, 
          i.cntr , NULL, :parameter.param);
      for j in (select * from city) loop 
       if j.fkkey=i.prkey then
        z:=j.c; 
        l_node:=Ftree.Add_Tree_Node('TREE.TREE', h_node, 
           Ftree.Parent_offset, ftree.NEXT_NODE, Ftree.LEAF_NODE, j.c, 
           NULL, :parameter.param); 
       ELSE 
        null;
       end if; 
      end loop; 
     end;
     end loop; 
    end;

    При запуске формы дерево заполняется значениями из таблиц. Далее мы рассмотрим несколько примеров, которые не только продемонстрируют нам методы пакета FTREE, но и расширят функциональность формы.

    Вы можете синхронизировать дерево с главным блоком, отражая перемещение на следующую запись в дереве, выделяя и развертывая соответствующий узел. Для того чтобы выполнить этот пример, создайте триггер WHEN-NEW-RECORD-INSTANCE для блока COUNTRY и напишите в нем нижеприведенный код.

    WHEN-NEW-RECORD-INSTANCE
    DECLARE
     Itree item := find_item('tree.tree');
     select_node ftree.node;
    begin
     select_node := ftree.find_tree_node(Itree, :prkey,
     ftree.find_next, ftree.node_value,
     ftree.root_node, ftree.root_node); 
     ftree.set_tree_selection(Itree, select_node, ftree.select_on); 
     ftree.set_tree_node_property(Itree, select_node, ftree.node_state, 
          ftree.expanded_node); 
    end;

    Запустите форму и выберите записи. Попробуйте перейти на следующую или предыдущую запись, и вы увидите, как синхронно разворачивается и выделяется узел в дереве при перемещении на новую запись. Теперь создадим кнопку, по нажатию которой будет удаляться выбранный элемент дерева. Для этого создайте кнопку и установите для нее метку "Удалить узел". Создайте триггер WHEN-BUTTON-PRESSED для кнопки и напишите в нем нижеприведенный код.

    WHEN-BUTTON-PRESSED. 
    Удаление выделенного узла
    DECLARE
     Itree item := find_item('tree.tree');
     select_node Ftree.NODE := Ftree.Get_Tree_Selection(Itree, :country.prkey);
    begin
     Ftree.Delete_Tree_Node(Itree, select_node);
    end;
    Страницы:

    Элемент Tree View является специфичным не только потому, что требует особых условий и настройки свойств, а еще и потому, что для управления этим элементом в Oracle Forms создан специальный встроенный пакет FTREE. Элемент дерево является очень функциональным, так как позволяет скоординировать и компактно отобразить большой набор данных, разбивая его на логические единицы - узлы. Вы можете заполнять деревья статически и динамически данными из таблиц. В дереве вы можете реализовать отношение Мастер-Деталь, выбирая в качестве родительского узла запись таблицы Мастер, а в качестве дочернего - запись из таблицы Деталь. Вы также можете использовать дерево как навигатор вашего приложения, в котором перечислены все блоки и элементы. Пакет FTREE содержит довольно небольшой объем процедур и функций, которые перечислены ниже:

  • ADD_TREE_DATA ;
  • ADD_TREE_NODE ;
  • DELETE_TREE_NODE ;
  • FIND_TREE_NODE ;
  • POPULATE_GROUP_FROM_TREE ;
  • POPULATE_TREE ;
  • SET_TREE NODE_PROPERTY.
  • Создание Tree View

    Tree View представляет собой прямоугольную область, в которой отображается иерархическое дерево. Для того чтобы создать дерево, выполните следующие действия:

  • Создайте новую форму и сохраните ее как TREE.
  • Находясь в навигаторе объектов, создайте два небазовых блока. Первый блок назовите " TREE ", а второй " CONTR ".
  • Находясь в редакторе разметки, создайте одну канву. Разместите на канве элемент Tree View и две кнопки.
  • Установите для элемента TREE VIEW блок TREE, а все остальные элементы ассоциируйте с блоком " CONTR ".
  • В этом примере мы создали дополнительный управляющий блок данных "CONTR" для последующего использования в примерах.

    Прежде чем построить дерево, рассмотрим основные методы пакета FTREE, которые нам для этого понадобятся.

    Функция ADD_TREE_NODE

    ADD_TREE_NODE (item_id [item_id] ITEM, node NODE, 
          offset_ type NUMBER, offset NUMBER, state NUMBER, 
         label VARCHAR2, icon VARCHAR2, value VARCHAR2) 
    RETURN FTREE.NODE

    - добавляет новый элемент в дерево.

    Метод Параметр Тип Значение
    FUNCTION ADD_TREE_NODE (параметры) RETURN NODE itemname [idname] VARCHAR2 [FORMS4C.ITEM] Определяет имя элемента или его идентификатор
    node FTREE.NODE Определяет вершину дерева
    offsettype NUMBER Определяет тип сдвига для вершины, возможные значения: PARENT_OFFSET, SIBLING_OFFSET
    offset NUMBER Определяет позицию новой вершины: если это PARENT_OFFSET, то позиция 1-n,, или LAST_CHILD. Если тип сдвига SIBLING_OFFSET, то позицией сдвига может быть NEXT_NODE или PREVIOUS_NODE
    state NUMBER Определяет состояние вершины: COLLAPSED_NODE, EXPANDED_NODE, LEAF_NODE
    label VARCHAR2 Отображаемый текст для вершины
    icon VARCHAR2 Имя файла иконки для вершины
    value VARCHAR2 Значение, которое содержит вершина
    Примечание:элемент дерево всегда должен размещаться в отдельном блоке и быть в нем единственным элементом. В предыдущем примере для того чтобы разместить кнопки, нам пришлось создать второй блок, так как блок, содержащий элемент Tree View, не может содержать других элементов. Если вы все же разместите еще один элемент в блоке "TREE", то получите ошибку "FRM-32089 - Деревья должны размещаться в однозаписных блоках с одним элементом".

    Следующий пример описывает процесс добавления нового элемента в существующее дерево.

    DECLARE
     Itree ITEM;
     top_node Ftree.Node;
     new_node Ftree.Node;
     i_value VARCHAR2(30);
    BEGIN
     Itree := Find_Item('tree_block.tree_item ');
     new_node := Ftree.Add_Tree_Node(Itree, Ftree.ROOT_NODE,
       Ftree.PARENT_OFFSET, Ftree.LAST_CHILD,
       Ftree.EXPANDED_NODE, i_value, NULL, i_value);
    END;

    Процедура DELETE_TREE_NODE

    DELETE_TREE_NODE (item_name [item_id] VARCHAR2, node FTREE.NODE) - эта процедура выполняет действие, обратное ADD_ TREE_NODE, то есть удаляет элемент дерева.

    Метод Параметр Тип Значение
    PROCEDURE DELETE_TREE_NODE(параметры) itemname [idname] VARCHAR2 [FORMS4C.ITEM] Определяет имя элемента или его идентификатор
    node FTREE.NODE Определяет вершину дерева, которую необходимо удалить

    Следующий пример описывает процесс удаления вершины и всех ее детей.

    DECLARE
     Itree item := find_item('tree_block.tree_item ');
     del_node Ftree.Node;
     i_value VARCHAR2(30);
    BEGIN
     del_node := Ftree.Find_Tree_Node(Itree, i_value,
      Ftree.FIND_NEXT, Ftree.NODE_LABEL,
      Ftree.ROOT_NODE, Ftree.ROOT_NODE);
     IF NOT Ftree.ID_NULL(del_node) then 
      Ftree.Delete_Tree_Node(Itree, del_node); 
     END IF; 
    END;

    Функция FTREE.GET_TREE_NODE_PARENT

    FTREE.GET_TREE_NODE_PARENT (item_name [item_id] VARCHAR2, node FTREE.NODE) - возвращает родителя указанной вершины дерева.

    Метод Параметр Тип Значение
    FUNCTION DELETE_TREE_NODE (параметры) RETURN NODE itemname [idname] VARCHAR2 [FORMS4C.ITEM] Определяет имя элемента или его идентификатор
    node FTREE.NODE Вершина дерева, для которой отыскивается родитель

    Следующий пример описывает процесс получения родителя указанного элемента.

    DECLARE
     Itree item := find_item('tree_block.tree_item ');
     par_node FTREE.NODE;
    BEGIN
     par_node := Ftree.Get_Tree_Node_Parent(Itree,
       :SYSTEM.TRIGGER_NODE);
     ...
    END;

    Функция FTREE.GET_TREE_NODE_PROPERTY

    FTREE.GET_TREE_NODE_PROPERTY (item_name [item_id] VARCHAR2, node NODE, property NUMBER) RETURN VARCHAR2 - возвращает значение свойства указанной вершины дерева.

    Метод Параметр Тип Значение
    FUNCTION GET_TREE_NODE_PROPERTY (параметры) RETURN VARCHAR2 itemname [idname] VARCHAR2 [FORMS4C.ITEM] Определяет имя элемента или его идентификатор
    node FTREE.NODE Вершина дерева, для которой отыскивается родитель
    property NUMBER Возвращает значение одного из перечисленных свойств: NODE_STATE, NODE_DEPTH, NODE_LABEL, NODE_ICON, NODE_VALUE

    Следующий пример проверяет состояние указанной вершины, и если она не раскрыта, то есть NODE_STATE установлено в COLLAPSED_ NODE, то вершина автоматически раскрывается, то есть NODE_STATE устанавливается в EXPANDED_NODE.

    DECLARE
     Itree item := find_item('tree_block.tree_item ');
    BEGIN
     IF Ftree.Get_Tree_Node_Property(Itree,
       :SYSTEM.TRIGGER_NODE, Ftree.NODE_STATE)=Ftree.COLLAPSED_NODE
     THEN 
      ftree.set_tree_node_property(Itree, 
        :SYSTEM.TRIGGER_NODE, ftree. node_state, ftree.expanded_node); 
     END IF; 
    END;

    Используйте функцию FTREE.GET_TREE_NODE_PROPERTY для получения значения вершины.

    DECLARE
     Itree item := find_item('tree_block.tree_item ');
    BEGIN
     Ftree.Get_Tree_Node_Property(Itree, :SYSTEM.TRIGGER_NODE, 
       Ftree.NODE_VALUE);
     ...
    END;

    Функция FTREE.GET_TREE_PROPERTY

    FTREE.GET_TREE_PROPERTY (item_name [item_id] VARCHAR2, property NUMBER) RETURN VARCHAR2 - возвращает значение свойства указанного элемента дерева.

    Метод Параметр Тип Значение
    FUNCTION GET_TREE_PROPERTY (параметры) RETURN VARCHAR2 itemname [idname] VARCHAR2 [FORMS4C.ITEM] Определяет имя элемента или его идентификатор
    property NUMBER Возвращает значение одного из перечисленных свойств: DATASOURCE, RECORD_GROUP, SET_TREE_PROPERTY, QUERY_TEXT, NODE_COUNT, SELECTION_COUNT, ALLOW_EMPTY_BRANCHES, ALLOW_MULTI-SELECT

    Следующий пример описывает процесс получения количества вершин указанного дерева.

    DECLARE
     Itree item := find_item('tree_block.tree_item ');
     node_cnt NUMBER;
    BEGIN
     node_cnt := Ftree.Get_Tree_Property(Itree,
     Ftree.NODE_COUNT);
     Message('Количество вершин дерева: '||node_cnt);
    END;

    Функция FTREE.GET_TREE_SELECTION

    GET_TREE_SELECTION (item_name [item_id] VARCHAR2, selection NUMBER) RETURN Ftree.NODE - возвращает выделенную вершину дерева.

    Метод Параметр Тип Значение
    FUNCTION GET_TREE_SELECTION (параметры) RETURN VARCHAR2 itemname [idname] VARCHAR2 [FORMS4C.ITEM] Определяет имя элемента или его идентификатор
    selection NUMBER Индекс выделенной вершины дерева

    Следующий пример описывает процесс получения выделенных элементов указанного дерева. Все элементы, помеченные как выделенные, будут удалены, причем удалять элементы нужно в обратном порядке, как показано в примере.

    DECLARE
     Itree item := find_item('tree_block.tree_item ');
     Select_cnt NUMBER;
     del_node FTREE.NODE;
    BEGIN
     Select_cnt:= Ftree.Get_Tree_Property(Itree,
     Ftree.SELECTION_COUNT);
     FOR i IN REVERSE 1..select_cnt LOOP
      del_node := Ftree.Get_Tree_Selection(Itree, i);
      Ftree.Delete_Tree_Node(Itree, del_node);
     END LOOP;
    END;

    Процедура FTREE.SET_TREE_NODE_PROPERTY

    SET_TREE_NODE_PROPERTY (item_name [item_id] VARCHAR2 [FORMS4C.ITEM], node FTREE.NODE, property NUMBER, value NUMBER [VARCHAR2]) - устанавливает свойства элемента дерева.

    Метод Параметр Тип Значение
    PROCEDURE SET_TREE_NODE_PROPERTY (параметры) RETURN VARCHAR2 item_name VARCHAR2 [id_name] [FORMS4C.ITEM] Определяет имя элемента или его идентификатор
    node FTREE.NODE Вершина дерева, для которой устанавливается свойство
    property NUMBER Устанавли вает одно из перечисленных свойств равным value: NODE_STATE, NODE_LABEL, NODE_ICON, NODE_VALUE
    value NUMBER [VARCHAR2] Значение, устанавливаемое для заданного свойства

    Следующий пример описывает процесс поиска корневого узла и его развертывания.

    DECLARE
     Itree item := find_item('tree_block.tree_item ');
     branch_node Ftree.NODE;
     i_value varchar2(30);
    begin
     select_node := Ftree.Find_Tree_Node(Itree, i_value,
       Ftree.FIND_NEXT, Ftree.NODE_VALUE,
       Ftree.ROOT_NODE, Ftree.ROOT_NODE); 
     ftree.set_tree_node_property(Itree, select_node, 
       ftree.node_state, ftree.expanded_node); 
    END;

    С помощью процедуры SET_TREE_NODE_PROPERTY вы можете менять иконку узла в зависимости от какого-либо условия, как показано в листинге 3.8.

    DECLARE
     Itree item := find_item('tree_block.tree_item ');
    BEGIN
     IF Ftree.Get_Tree_Node_Property(Itree,
      :SYSTEM.TRIGGER_NODE, Ftree.NODE_STATE)=Ftree.COLLAPSED_NODE
     THEN Ftree.Set_Tree_Node_Property(Itree, :SYSTEM.TRIGGER_NODE, Ftree.NODE_ICON, 'Close'); 
     ELSIF 
      Ftree.Get_Tree_Node_Property(Itree, :SYSTEM.TRIGGER_NODE, 
            Ftree.NODE_STATE)= Ftree.EXPANDED_NODE
     THEN 
      Ftree.Set_Tree_Node_Property(Itree, :SYSTEM.TRIGGER_NODE, 
        Ftree.NODE_ICON, 'Open'); 
     END IF; 
    END;

    Процедура SET_TREE_PROPERTY

    SET_TREE_PROPERTY (item_name [item_id] VARCHAR2 [FORMS4C.ITEM], property NUMBER, value NUMBER [VARCHAR2, RECORDGROUP]) - устанавливает значение указанного свойства дерева.

    Метод Параметр Тип Значение
    PROCEDURE SET_TREE_PROPERTY (параметры) itemname [idname] VARCHAR2 [FORMS4C.ITEM] Определяет имя элемента или его идентификатор
    property NUMBER Устанавливает одно из перечисленных свойств равным value: RECORD_GROUP, QUERY_TEXT, ALLOW_EMPTY_BRANCHES
    value NUMBER[VARCHAR2,RECORDGROUP] Значение, устанавливаемое для заданного свойства. Для ALLOW_EMPTY_BRANCHES это всегда PROPERTY_TRUE или PROPERTY_FALSE

    В следующем примере разрешается наличие в дереве пустых узлов, то есть элементов, не содержащих детей.

    DECLARE
     Itree item := find_item('tree_block.tree_item ');
    BEGIN
     Ftree.Set_Tree_Property(Itree, Ftree.ALLOW_EMPTY_BRANCHES,
      property_true);
    END;

    Процедура SET_TREE_SELECTION

    SET_TREE_SELECTION item_name [item_id] VARCHAR2 [FORMS4C. ITEM], node NODE, selection_type NUMBER) - устанавливает или сбрасывает выделение указанной вершины.

    Метод Параметр Тип Значение
    PROCEDURE SET_TREE_SELECTION (параметры) itemname [idname] VARCHAR2 [FORMS4C.ITEM] Определяет имя элемента или его идентификатор
    node NUMBER Вершина дерева, для которой устанавливается свойство
    selectiontype NUMBER[VARCHAR2,RECORDGROUP] Определяет тип выделения: SELECT_ON, SELECT_OFF, SELECT_TOGGLE

    Следующий пример описывает процесс поиска корневого узла и его выделение.

    DECLARE
     Itree item := find_item('tree_block.tree_item ');
     select_node Ftree.NODE;
     i_value VARCHAR2(30);
    BEGIN
     select_node:= Ftree.Find_Tree_Node(Itree, i_value,
       Ftree.FIND_NEXT, Ftree.NODE_VALUE,
       Ftree.ROOT_NODE, Ftree.ROOT_NODE); 
     Ftree.Get_Tree_Property(Itree, select_node, ftree.select_on); 
    END;

    Теперь, когда мы рассмотрели все основные процедуры и функции для работы с деревом, можно приступить к его построению. Для начала выполним простой пример, который описывает создание корневого и дочернего узла, причем для построения дерева мы будем использовать шаблон, созданный в предыдущем примере.

  • Установите для кнопки метку "Добавить родительский узел" и создайте для нее событие WHEN-BUTTON-PRESSED. В теле триггера напишите и скомпилируйте строки, которые приведены ниже.
    WHEN-BUTTON-PRESSED
    DECLARE
     r_Node Ftree.Node;
     c_Node Ftree.Node;
    BEGIN
     r_Node:=Ftree.Add_Tree_Node('TREE.TREE',
     Ftree.ROOT_NODE,
     Ftree.PARENT_OFFSET,
     Ftree.LAST_CHILD,
     Ftree.EXPANDED_NODE, 'Главный' , NULL, '1');
    END;
  • Установите для второй кнопки метку "Добавить дочернюю ветку " и создайте для нее событие WHEN-BUTTON-PRESSED. В теле триггера напишите и скомпилируйте строки, которые приведены ниже.
    WHEN-BUTTON-PRESSED
    DECLARE
     h_Node Ftree.Node;
     l_Node Ftree.Node;
    begin
     h_Node:=Ftree.Add_Tree_Node(' TREE.TREE ',
     Ftree.ROOT_NODE,
     Ftree.PARENT_OFFSET,
     Ftree.LAST_CHILD,
     Ftree.EXPANDED_NODE, 'Дочерний' , NULL, '1');
     l_node:=Ftree.Add_Tree_Node('TREE.TREE', h_node, Ftree.Parent_offset,
     ftree.NEXT_NODE,
     Ftree.LEAF_NODE,
     'Дочерний', NULL, '2'); 
    end;
  • Результат работы программы показан на рис. 1. Далее приведен пример с заполнением дерева моделью Мастер-Деталь.

  • Для создания блоков COUNTRY и CITY выполните скрипт, приведенный в листинге 3.12.
    SQL: CREATE TABLE COUNTRY
    (PRkey number PRIMARY KEY, cntr varchar2(100)) /
    SQL: CREATE TABLE CITY (FKkey number, town varchar2(100)) /
    -- вставка значений в таблицу COUNTRY
    SQL: INSERT INTO COUNTRY VALUES (1,'Украина'); 
      SQL: INSERT INTO COUNTRY VALUES (2,'Россия');
        SQL: INSERT INTO COUNTRY VALUES (3,'Германия');
    -- вставка значений в таблицу CITY
    SQL: INSERT INTO CITY VALUES  (1,'Киев');
    SQL: INSERT INTO CITY VALUES  (1,'Львов');
    SQL: INSERT INTO CITY VALUES  (1,'Мариуполь');
    SQL: INSERT INTO CITY VALUES  (2,'Москва');
    SQL: INSERT INTO CITY VALUES  (2,'Санкт-Петербург');
    SQL: INSERT INTO CITY VALUES  (2,'Калининград');
    SQL: INSERT INTO CITY VALUES  (3,'Берлин');
    SQL: INSERT INTO CITY VALUES  (3,'Франкфурт');
    SQL: INSERT INTO CITY VALUES  (3,'Магдебург');
  • Сохраните модуль как relation_tree.
  • Создайте два блока COUNTRY и CITY и свяжите их между собой, установив JOIN CONDITION равным COUNTRY.PRKEY=CITY. FKKEY.
  • Находясь в навигаторе объектов, создайте небазовый блок и назовите его " TREE ".
  • Находясь в редакторе разметки, создайте одну канву. Разместите на канве элемент Tree View и назовите его TREE.
  • Создайте триггер WHEN-NEW-FORM-INSTANCE и напишите в нем нижеприведенный код.
  • WHEN-NEW-FORM-INSTANCE
    DECLARE
     z varchar2(100);
     x number;
     h_Node Ftree.Node;
     l_Node Ftree.Node;
     cursor c1 is select * from country;
     cursor a1 is select * from city;
     c2 c1%rowtype;
     a2 a1%rowtype;
    begin
     open c1;
     for i in (select * from country) loop 
     begin
      :parameter.param:=:parameter.param+1; 
      h_Node:=Ftree.Add_Tree_Node('TREE.TREE', ftree.ROOT_NODE, 
          Ftree.PARENT_OFFSET, Ftree.LAST_CHILD, Ftree.EXPANDED_NODE, 
          i.cntr , NULL, :parameter.param);
      for j in (select * from city) loop 
       if j.fkkey=i.prkey then
        z:=j.c; 
        l_node:=Ftree.Add_Tree_Node('TREE.TREE', h_node, 
           Ftree.Parent_offset, ftree.NEXT_NODE, Ftree.LEAF_NODE, j.c, 
           NULL, :parameter.param); 
       ELSE 
        null;
       end if; 
      end loop; 
     end;
     end loop; 
    end;

    При запуске формы дерево заполняется значениями из таблиц. Далее мы рассмотрим несколько примеров, которые не только продемонстрируют нам методы пакета FTREE, но и расширят функциональность формы.

    Вы можете синхронизировать дерево с главным блоком, отражая перемещение на следующую запись в дереве, выделяя и развертывая соответствующий узел. Для того чтобы выполнить этот пример, создайте триггер WHEN-NEW-RECORD-INSTANCE для блока COUNTRY и напишите в нем нижеприведенный код.

    WHEN-NEW-RECORD-INSTANCE
    DECLARE
     Itree item := find_item('tree.tree');
     select_node ftree.node;
    begin
     select_node := ftree.find_tree_node(Itree, :prkey,
     ftree.find_next, ftree.node_value,
     ftree.root_node, ftree.root_node); 
     ftree.set_tree_selection(Itree, select_node, ftree.select_on); 
     ftree.set_tree_node_property(Itree, select_node, ftree.node_state, 
          ftree.expanded_node); 
    end;

    Запустите форму и выберите записи. Попробуйте перейти на следующую или предыдущую запись, и вы увидите, как синхронно разворачивается и выделяется узел в дереве при перемещении на новую запись. Теперь создадим кнопку, по нажатию которой будет удаляться выбранный элемент дерева. Для этого создайте кнопку и установите для нее метку "Удалить узел". Создайте триггер WHEN-BUTTON-PRESSED для кнопки и напишите в нем нижеприведенный код.

    WHEN-BUTTON-PRESSED. 
    Удаление выделенного узла
    DECLARE
     Itree item := find_item('tree.tree');
     select_node Ftree.NODE := Ftree.Get_Tree_Selection(Itree, :country.prkey);
    begin
     Ftree.Delete_Tree_Node(Itree, select_node);
    end;
    Вернуться к учебному плану