2015-03-31 2 views
0

Мне нужно отобразить главное меню в TVirtualStringTree - каждый элемент меню имеет категорию. Категории будут составлять корневые узлы дерева, а под каждым корневым узлом категории будут элементы меню.VirtualStringTree - Не удается корректно работать с родительскими дочерними узлами

наборов данных для полей Категории и MenuItems выглядеть следующим образом: dataset structure

Мой код в OnInitNode прокручивается через записях Категория набора данных и загружает эти пункты меню для каждой категории в качестве дочерних узлов. Однако у меня что-то не так (см. Изображение), а узлы категории - это один и тот же текст, что означает, что набор данных не прокручивается до следующей записи.

Кажется, что эта строка кода в InitNode событие вызывает его, чтобы выйти из цикла и, как представляется, является причиной проблемы:

Sender.ChildCount[Node] := x; 

Но то, что это правильный путь, чтобы сделать дочерние узлы ?

Это мой код:

type 
    TTreeCategoryData = record 
    ID: Integer; 
    DispText: String; 
    end; 

    PTreeCategoryData = ^TTreeCategoryData; 

    TTreeMenuItemData = record 
    ID: Integer; 
    CategoryID: Integer; 
    DispText: String; 
    ClassName: String; 
    end; 

    PTreeMenuItemData = ^TTreeMenuItemData; 

    Tvstmainmenu_CategoryNodeData = record 
    TreeCategoryData: PTreeCategoryData; 
    end; 

    Pvstmainmenu_CategoryNodeData = ^Tvstmainmenu_CategoryNodeData; 

    Tvstmainmenu_MenuItemNodeNodeData = record 
    TreeMenuItemData: PTreeMenuItemData; 
    end; 

    Pvstmainmenu_MenuItemNodeNodeData = ^Tvstmainmenu_MenuItemNodeNodeData; 


procedure TfmMain.FormShow(Sender: TObject); 
var 
    x: Integer; 
begin 
    datamod.uspspmenucatgy_S.PrepareSQL(True); 
    datamod.uspspmenucatgy_S.Open; 

    x := datamod.uspspmenucatgy_S.RecordCount; 
    vstmainmenu.RootNodeCount := x; 
end; 

procedure TfmMain.vstmainmenuFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); 
var 
    CategoryNodeData: Pvstmainmenu_CategoryNodeData; 
    MenuItemNodeNodeData: Pvstmainmenu_MenuItemNodeNodeData; 
begin 
    if (Sender.GetNodeLevel(Node) = 0) then 
    begin 
    CategoryNodeData := Sender.GetNodeData(Node); 

    if Assigned(CategoryNodeData) and Assigned(CategoryNodeData.TreeCategoryData) then 
    begin 
     Dispose(CategoryNodeData.TreeCategoryData); 
    end; 
    end 
    else if (Sender.GetNodeLevel(Node) = 1) then 
    begin 
    MenuItemNodeNodeData := Sender.GetNodeData(Node); 

    if Assigned(MenuItemNodeNodeData) and Assigned(MenuItemNodeNodeData.TreeMenuItemData) then 
    begin 
     Dispose(MenuItemNodeNodeData.TreeMenuItemData); 
    end; 
    end; 

end; 

procedure TfmMain.vstmainmenuGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; 
    TextType: TVSTTextType; var CellText: string); 
var 
    CategoryNodeData: Pvstmainmenu_CategoryNodeData; 
    MenuItemNodeNodeData: Pvstmainmenu_MenuItemNodeNodeData; 

    TreeCategoryData: PTreeCategoryData; 
    TreeMenuItemData: PTreeMenuItemData; 
begin 

    if (Sender.GetNodeLevel(Node) = 0) then 
    begin 
    CategoryNodeData := Sender.GetNodeData(Node); 

    if Assigned(CategoryNodeData) and Assigned(CategoryNodeData.TreeCategoryData) then 
    begin 
     TreeCategoryData := CategoryNodeData.TreeCategoryData; 

     CellText := TreeCategoryData^.DispText; 
    end; 
    end 
    else if (Sender.GetNodeLevel(Node) = 1) then 
    begin 
    MenuItemNodeNodeData := Sender.GetNodeData(Node); 

    if Assigned(MenuItemNodeNodeData) and Assigned(MenuItemNodeNodeData.TreeMenuItemData) then 
    begin 
     TreeMenuItemData := MenuItemNodeNodeData.TreeMenuItemData; 

     CellText := TreeMenuItemData^.DispText; 
    end; 
    end; 

end; 

procedure TfmMain.vstmainmenuInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; 
    var InitialStates: TVirtualNodeInitStates); 
var 
    CategoryNodeData: Pvstmainmenu_CategoryNodeData; 
    MenuItemNodeNodeData: Pvstmainmenu_MenuItemNodeNodeData; 

    x: Integer; 
begin 

    if (Sender.GetNodeLevel(Node) = 0) then 
    begin 
    CategoryNodeData := Sender.GetNodeData(Node); 
    CategoryNodeData.TreeCategoryData := New(PTreeCategoryData); 

    with CategoryNodeData.TreeCategoryData^ do 
    begin 
     ID := datamod.uspspmenucatgy_Srow_id.AsInteger; 
     DispText := datamod.uspspmenucatgy_Scategory.AsString; 
    end; 

    // :Pcategory_id 
    datamod.uspspmenu_S.ParamByName('Pcategory_id').AsInteger := datamod.uspspmenucatgy_Srow_id.AsInteger; 
    datamod.uspspmenu_S.PrepareSQL(True); 
    if (datamod.uspspmenu_S.State = dsBrowse) then 
     datamod.uspspmenu_S.Refresh 
    else 
     datamod.uspspmenu_S.Open; 

    x := datamod.uspspmenu_S.RecordCount; 

    Sender.ChildCount[Node] := x; 

    datamod.uspspmenucatgy_S.Next; 
    end 
    else if (Sender.GetNodeLevel(Node) = 1) then 
    begin 
    MenuItemNodeNodeData := Sender.GetNodeData(Node); 
    MenuItemNodeNodeData.TreeMenuItemData := New(PTreeMenuItemData); 

    with MenuItemNodeNodeData.TreeMenuItemData^ do 
    begin 
     ID := datamod.uspspmenu_Srow_id.AsInteger; 
     CategoryID := datamod.uspspmenucatgy_Srow_id.AsInteger; 
     DispText := datamod.uspspmenu_Smenuitem.AsString; 
     ClassName := datamod.uspspmenu_Stframeclass.AsString; 
    end; 

    datamod.uspspmenu_S.Next; 
    end; 

end; 

Вот что происходит. Каждый корневой узел (родительский) должен быть другим, но это не так. Дальше дочерние узлы для 2-го корневого узла должны быть разными, но это, кажется, застрял на последнем дочернего узла 1-го корневого узла:

erroneous rendering!

Спасибо заранее!

ответ

0

Попробуйте альтернативный подход, как создание узлов в отдельной процедуре и т.д .:

procedure TfrmMain.LoadTree; 
var 
    LTreeCategoryData: PTreeCategoryData; 
    LCategoryNode: PVirtualNode; 
begin 
    datamod.uspspmenucatgy_S.PrepareSQL(True); 
    datamod.uspspmenucatgy_S.Open; 
    while not datamod.uspspmenucatgy_S.Eof do 
    begin 
    // 1. create parent node itself 
    LTreeCategoryData := New(PTreeCategoryData); 
    with LTreeCategoryData^ do 
    begin 
     ID := datamod.uspspmenucatgy_Srow_id.AsInteger; 
     DispText := datamod.uspspmenucatgy_Scategory.AsString; 
    end; 
    LCategoryNode := vstmainmenu.AddChild(vstmainmenu.RootNode, LTreeCategoryData); 

    // 2. create child nodes 
    datamod.uspspmenu_S.ParamByName('Pcategory_id').AsInteger := datamod.uspspmenucatgy_Srow_id.AsInteger; 
    datamod.uspspmenu_S.PrepareSQL(True); 
    datamod.uspspmenu_S.Open; 
    while not datamod.uspspmenu_S.Eof do 
    begin 
     LTreeMenuItemData := New(PTreeMenuItemData); 

     with LTreeMenuItemData^ do 
     begin 
     ID := datamod.uspspmenu_Srow_id.AsInteger; 
     CategoryID := datamod.uspspmenucatgy_Srow_id.AsInteger; 
     DispText := datamod.uspspmenu_Smenuitem.AsString; 
     ClassName := datamod.uspspmenu_Stframeclass.AsString; 
     end; 

     vstmainmenu.AddChild(LCategoryNode, LTreeMenuItemData); 

     datamod.uspspmenu_S.Next; 
    end; 
    datamod.uspspmenu_S.Close; 

    datamod.uspspmenucatgy_S.Next; 
    end; 
    datamod.uspspmenucatgy_S.Close; 
end; 

Просто назвать эту новую процедуру всякий раз, когда вы хотите, чтобы загрузить все дерево.

+0

Спасибо! Он работал правильно. –

1

Когда вы инициализируете родительский (категориальный) узел, вы устанавливаете SQL, открываете запрос и назначаете количество дочерних узлов. Вы предполагаете, что эти узлы будут немедленно инициализированы, поэтому запрос будет пройден сразу.

Это не так, как это управление деревом работает. Дети инициализируются по требованию, а не в определенном порядке. Возможно, что все родительские узлы инициализируются перед любыми дочерними элементами, что объясняет, почему многие из детей имеют один и тот же текст - вы отбросили два запроса с третьим, поэтому оставшиеся дети повторно использовали последний действительный результат из самого последнего запроса ,

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

В противном случае вам нужно использовать AddNode, чтобы добавить узлы в дерево. Итерации по результатам запроса и добавление узла для каждой записи по мере ее возникновения.

У узлов категории, вероятно, все одинаковые названия по аналогичной причине. Пусть ваш код обработки запросов управляет добавлением узлов, а не наоборот.

+0

Спасибо, Роб. Это тот ответ, который я искал - «причина» проблемы. –