1

TVirtualStringTree で Main-Menu をレンダリングする必要があります。各メニュー項目にはカテゴリがあります。カテゴリはツリーのルート ノードを構成し、各カテゴリ ルート ノードの下にメニュー項目があります。

Categories と MenuItems のデータセット フィールドは次のようになります。 データセットの構造

OnInitNode の私のコードは、カテゴリ データセットのレコードをスクロールし、各カテゴリのメニュー項目を子ノードとして読み込みます。ただし、何か問題があり (画像を参照)、Category ノードはすべて同じテキストです。つまり、データセットが次のレコードにスクロールしていません。

イベント内のこのコード行が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 番目のルート ノードの最後の子ノードでスタックしているようです。

間違ったレンダリング!

前もって感謝します!

4

2 に答える 2

1

別の手順でノードを作成するなど、別の方法を試してください。

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;

ツリー全体をロードしたいときはいつでも、この新しいプロシージャを呼び出すだけです。

于 2015-03-31T16:10:52.557 に答える
1

親 (カテゴリ) ノードを初期化するときは、SQL を設定し、クエリを開き、子ノードの数を割り当てます。これらのノードはすぐに初期化されると想定しているため、クエリはすぐにトラバースされます。

それは、このツリー コントロールがどのように機能するかではありません。子は、定義された順序ではなく、オンデマンドで初期化されます。すべての親ノードが子の前に初期化される可能性があります。これが、子の多くが同じテキストを持っている理由を説明しています。3 番目のクエリで 2 つのクエリを破棄したため、残りの子は最新のクエリからの最後の有効な結果を再利用し続けました。 .

何年も前に、ツリー コントロールのデータベース対応バージョンがありました。そのようなコントロールがまだいくつかあるかもしれません。それらはあなたの目的により適しているかもしれません。

それ以外の場合は、 を使用AddNodeしてノードをツリーに追加する必要があります。クエリの結果を繰り返し処理し、レコードごとにノードを追加します。

同様の理由で、カテゴリ ノードはおそらくすべて同じタイトルになっています。クエリ処理コードがノードの追加を駆動するようにします。その逆ではありません。

于 2015-04-01T05:35:09.100 に答える