I have a table like this:
id parent_id name
1 1 Root
2 1 Car
3 1 Plane
4 2 BMW
5 4 CLK
How can I dynamically create popup menu with all subitems in Delphi?
This is how it should look like:
This solution requires parent_id of root to be 0, tested with
should by optimized, have just a lack of time ...
Too many solutions for such a simple problem. Too bad you got ordered ID's because without ordered ID's things would have been more fun. Here's my own solution. On an empty form drop a button, a TClientDataSet and a TPopupMenu. Make the form's PopupMenu = PopupMenu1 so you can see the result. Add this to Button1.OnClick:
Note: I'm intentionally using TClientDataSet and not a real Query. This question is not about the query and this solution works with whatever TDataSet descendant you throw at it. Just make sure the result set is ordered on
id
, or else you could see the child nodes before the parents. Also note, half the code is used to fill up the ClientDataSet with the sample data in the question!Interesting conundrum ...another late night thought, a practical answer for re-use :)
Make a derived component:
with code
end;
Main form, Assumes your data:
You could derive a TCascasePopupMenu and put it on the palette :)
Assuming root element has NULL as Parent_ID you can issue the request
You would also cache in-memory created menu items:
var MI_by_id: TDictionary<integer, TMenuItem>;
The traversing through the results would look like
Actually, since we made sort upon Parent_ID on the query, all the children for given parent make single continuous list, so could be better to remove populated parents from the dictionary after we populated last child (i.e. after parent_ID got new value) and caching previously found parent otherwise in another local variable (instead of making yet another search through the dictionary). However reasonable size for human-targeted menu should be much less to worth this. But you have to understand this approach most probably scales as O(n*n) thus would start loose speed very fast as the table grows.
Note: this also requires that for every non-root element ID > ParentID (put CHECK CONSTRAINT on the table)
This would lead to BMW tied to create before its parent CLK created. Violation for that conditions can be overcome by few means:
select <items> where Parent_id is null
, then for each of the added menu items doselect <items> where Parent_id = :current_memuitem_id
and so on that. This is like VirtualTreeView would workTry this
Taken from http://www.greatis.com/delphicb/tips/lib/components-addmenuitem.html