sql - Delphi中从sql server表动态创建弹出菜单树

标签 sql delphi menu tree delphi-xe2

我有一个这样的表:

id     parent_id     name
1          1         Root
2          1         Car
3          1         Plane
4          2         BMW
5          4         CLK

如何在 Delphi 中动态创建包含所有子项的弹出菜单?

它应该是这样的:

image

最佳答案

假设根元素的 Parent_ID 为 NULL,您可以发出请求

 Select ID, Parent_ID, Name from all_my_menus 
   order by Parent_ID nulls first, ID 
   where Menu_ID = :MenuIDParameter

1   <NULL>    Root
8   <NULL>    another root
2        1    Car
4        1    Plane
3        2    BMW
5        4    CLK

您还可以缓存内存中创建的菜单项:var MI_by_id: TDictionary<integer, TMenuItem>;

遍历结果看起来像

var MI: TMenuItem;
    MI_by_id: TDictionary<integer, TMenuItem>;
begin 
  MI_by_id := TDictionary<integer, TMenuItem>.Create;
  try
    While not Query.EOF do begin
        MI := TMenuItem.Create(Self);
        MI.Caption := Query.Fields[2].AsString;
        MI.Tag := Query.Fields[0].AsInteger; // ID, would be helpful for OnClick event
        MI.OnClick := ...some click handler

        if Query.Fields[1].IsNull {no parent}
           then MainMenu.Items.Add(MI)
           else MI_by_id.Items[Query.Fields[1].AsInteger].Add(MI);

        MI_by_id.Add(MI.Tag, MI); //save shortcut to potential parent for future searching
        Query.Next;
    end;
  finally 
    MI_by_id.Free;
  end;
end;

实际上,由于我们对查询中的 Parent_ID 进行了排序,给定父级的所有子级都会生成单个连续列表,因此在填充最后一个子级后(即在parent_ID获得新值之后),最好从字典中删除填充的父级并将先前找到的父项缓存在另一个局部变量中(而不是通过字典进行另一次搜索)。 然而,以人为本的菜单的合理大小应该远不值得这样做。但您必须了解这种方法很可能会扩展为 O(n*n),因此随着表的增长,速度会非常快。

注意:这还要求每个非根元素 ID > ParentID(在表上放置 CHECK CONSTRAINT)

1   <NULL>    Root
8   <NULL>    another root
7        1    Plane
3        4    BMW
4        7    CLK
5        8    Car

这将导致 BMW 在其母公司 CLK 创建之前绑定(bind)创建。 违反该条件可以通过以下几种方式克服:

  • 递归加载:select <items> where Parent_id is null ,然后对于每个添加的菜单项执行 select <items> where Parent_id = :current_memuitem_id等等。这就像 VirtualTreeView 可以工作
  • 要求 SQL 服务器对树进行排序和展平 - 这通常称为自递归 SQL 选择,并且与服务器相关。
  • 再引入一个集合变量 - 没有父项的菜单项。将每个新项目添加到菜单后,应搜索此集合是否有待处理的子项可从中提取并移动到新创建的父项中。

关于sql - Delphi中从sql server表动态创建弹出菜单树,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14356418/

相关文章:

delphi - Delphi组件的编程

user-interface - 在 "..."的菜单中,应该使用省略号还是只使用三个点?

SQL 查询顺序错误,不知道为什么

java - 原生sql查询位置

sql - 删除具有跨多个值的开始和结束时间戳的部分/完全重叠事件

delphi - TListView 中的边框颜色 (Delphi)

delphi - TWebbrowser 中烦人的点击声

mysql - 每个 id 选择一行,条件为 nonid 字段 | Magento 选择送货地址

html - 在多个页面上有一个菜单?

python - 使用 python 构建嵌套菜单