delphi cxTreeList 实现动态多级菜单的功能

创建 Menu 表

CREATE TABLE Menu (
    MenuID INT PRIMARY KEY,
    ParentMenuID INT NULL,
    Title NVARCHAR(100) NOT NULL,
    URL NVARCHAR(255),
    OrderNumber INT,
    IsActive BIT NOT NULL DEFAULT 1,
);

插入示例数据

INSERT INTO Menu (MenuID, ParentMenuID, Title, URL, OrderNumber, IsActive) VALUES
(1, 0, '主页', '/', 1, 1),
(2, 0, '博客', '/blog', 2, 1),
(3, 0, '关于我们', '/about', 3, 1),
(4, 0, '联系我们', '/contact', 4, 1),
(5, 2, '技术', '/blog/tech', 1, 1),
(6, 5, 'SQL Server', '/blog/tech/sqlserver', 1, 1),
(7, 5, 'Python', '/blog/tech/python', 2, 1),
(8, 2, '文学', '/blog/literature', 2, 1),
(9, 3, '公司简介', '/about/company-profile', 1, 1),
(10, 9, '我们的历史', '/about/company-history', 1, 1),
(11, 9, '我们的团队', '/about/company-team', 2, 1);

实现代码,已经加了详细注释

procedure TForm1.load_menu;
var
  Node, ParentNode: TcxTreeListNode;
  MenuItemID, ParentID: Integer;

  // 定义一个递归函数,用于在树节点中查找指定ID的节点
  function FindNodeByID(RootNode: TcxTreeListNode; NodeID: Integer): TcxTreeListNode;
  var
    I: Integer;
    Node: TcxTreeListNode;
  begin
    Result := nil;
    // 遍历当前节点的所有子节点
    for I := 0 to RootNode.Count - 1 do
    begin
      Node := RootNode.Items[I];
      // 如果找到节点ID匹配的节点,则返回该节点
      if Node.Values[0] = NodeID then
      begin
        Result := Node;
        Exit; // 退出函数
      end;
      // 否则递归地在当前子节点中查找
      Result := FindNodeByID(Node, NodeID);
      // 如果找到了匹配的节点,则直接返回结果
      if Assigned(Result) then
        Exit; // 退出函数
    end;
  end;

begin
  // 关闭查询,清除SQL语句,设置新的查询语句
  FDQuery1.Close;
  FDQuery1.SQL.Clear;
  FDQuery1.SQL.Add('SELECT MenuID, ParentMenuID, Title FROM db.dbo.Menu ORDER BY MenuID');
  FDQuery1.Open;

  // 如果查询结果不为空,则开始处理
  if not FDQuery1.IsEmpty then
  begin
    FDQuery1.First; // 定位到查询结果的第一条记录
    // 遍历查询结果的每一条记录
    while not FDQuery1.Eof do
    begin
      MenuItemID := FDQuery1.FieldByName('MenuID').AsInteger; // 获取菜单ID
      ParentID := FDQuery1.FieldByName('ParentMenuID').AsInteger; // 获取父菜单ID

      // 根据父菜单ID确定父节点
      if ParentID = 0 then
        ParentNode := cxTreeList1.Root // 如果父菜单ID为0,则父节点是根节点
      else
        ParentNode := FindNodeByID(cxTreeList1.Root, ParentID); // 否则通过递归查找父节点

      // 如果找到了父节点,则添加当前菜单节点作为其子节点
      if Assigned(ParentNode) then
      begin
        Node := cxTreeList1.AddChild(ParentNode); // 添加子节点
        Node.Values[0] := MenuItemID; // 设置节点的第一列值为菜单ID
        Node.Values[1] := FDQuery1.FieldByName('Title').AsString; // 设置节点的第二列值为菜单标题
        Node.Values[2] := FDQuery1.FieldByName('Url').AsString; // 设置节点的第二列值为导航地址
      end;

      FDQuery1.Next; // 移动到查询结果的下一条记录
    end;
  end;
end;

效果

 

posted @ 2024-06-28 17:27  liessay  阅读(32)  评论(0编辑  收藏  举报