2015-03-31 36 views
0

我需要在TVirtualStringTree中呈現Main-Menu - 每個菜單項都有一個Category。類別將組成樹的根節點,並且在每個類別根節點下,將成爲菜單項。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; 

這裏是發生了什麼。每個根節點(父)應該是不同的,但它不是。更進一步地,第二根節點應該是不同的子節點,但它似乎被卡住第一根節點的最後一個子節點上:

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

謝謝!它工作正常。 – 2015-04-01 09:15:37

1

初始化父(類)節點時,可以設置SQL,打開查詢並指定子節點的數量。你假設這些節點會立即被初始化,所以查詢會立即被遍歷。

這不是這個樹控制的工作原理。兒童按要求初始化,而不是按照任何明確的順序。所有父節點都可能在任何子節點之前被初始化,這就解釋了爲什麼很多子節點具有相同的文本 - 您放棄了第三個查詢中的兩個查詢,因此剩下的子節點不斷重用最近一次查詢的最後一個有效結果。

幾年前,有一個數據感知版本的樹控件;可能還會有一些這樣的控制。它們可能更適合你的目的。

否則,您應該做的是使用AddNode將節點添加到樹中。遍歷查詢結果並在遇到它時爲每條記錄添加一個節點。

由於類似的原因,類別節點可能都具有相同的標題。讓您的查詢處理代碼驅動添加節點,而不是相反。

+0

謝謝Rob。這是我正在尋找的答案 - 問題的「原因」。 – 2015-04-01 06:18:28