I'm trying to implement an expand/collapse option in the Delphi DBGrid. Sadly it is not a default supported option. The data used for display is comming from an ADOStoredProcedure.
The function has to be made for the DBGrid, using a alternative component lib is not an option. The SMDBGrid is avalible though (also does not support e/c)
Searching Google has not given me anything usefull yet. I'm wondering if anyone here has tackled this problem or an idea of how to go at this.
Thanks in advance!
Took some time but I managed to create te functionality for the DBGrid using a dynamic filter on the dataset. I'll post the code for someone who would need this functionality.
Class to store expanded items
type
//Store ID's used to keep expanded items
TPlanningFilterItem = class(TObject)
public
Sublevel, ProjectID, OnderdeelID, MedewerkerID: integer;
end;
Capture indicator click
procedure TFPlanningOverzicht.GridPlanningDblClick(Sender: TObject);
var
P: TPoint;
C: TGridCoord;
begin
GetCursorPos(P);
P := (Sender as TCustomGrid).ScreenToClient(P);
C := (Sender as TCustomGrid).MouseCoord(P.X, P.Y);
//Only capture indicator row X = 0
//Ignore title indicator Y > 1
if (C.X = 0) AND (C.Y > 0) then
DatasetFilterToevoegenVerwijderen;
FilterDataSet;
begin
end;
end;
Add or remove filter
procedure TFPlanningOverzicht.DatasetFilterToevoegenVerwijderen;
var
newFilterItem: TPlanningFilterItem;
tmp: TPlanningFilterItem;
I: Integer;
begin
newFilterItem := TPlanningFilterItem.Create;
newFilterItem.Sublevel := DPlanning.PlanningOverzicht.FieldByName('SUBLEVEL').AsInteger;
newFilterItem.ProjectID := DPlanning.PlanningOverzicht.FieldByName('ProjectID').AsInteger;
newFilterItem.OnderdeelID := DPlanning.PlanningOverzicht.FieldByName('OnderdeelID').AsInteger;
newFilterItem.MedewerkerID := DPlanning.PlanningOverzicht.FieldByName('MedewerkerID').AsInteger;
//Ignore expand when deepest lvl reached
if newFilterItem.Sublevel > 2 then
Exit;
for I := 0 to GridFilterItems.Count - 1 do
begin
//Compare to existing
tmp := GridFilterItems.Items[I];
if (tmp.Sublevel = newFilterItem.Sublevel) AND
(tmp.ProjectID = newFilterItem.ProjectID) AND
(tmp.OnderdeelID = newFilterItem.OnderdeelID) AND
(tmp.MedewerkerID = newFilterItem.MedewerkerID)
then
begin
//If item currently expanded collapse and exit
GridFilterItems.Delete(I);
Exit;
end;
end;
//Item not yet expanded, so expand
GridFilterItems.Add(newFilterItem);
end;
Applying the filter
procedure TFPlanningOverzicht.FilterDataSet;
var
I: integer;
tmp: TPlanningFilterItem;
Filter: string;
C: Integer;
begin
//Always show top level items
Filter := '(SUBLEVEL = ''' + IntToStr(1) + ''' ) OR ';
for I := 0 to GridFilterItems.Count - 1 do
begin
tmp := GridFilterItems[I];
//Expand when 1st row selected (shoud be written to your case)
if (tmp.Sublevel= 1) then
begin
Filter := Filter +
'(MedewerkerID = ''' + IntToStr(tmp.MedewerkerID) + ''' AND ' +
'SUBLEVEL = ''' + IntToStr(2) + ''' ) OR ';
end
else
begin
//Expands for the second level (shoud be written to your case)
Filter := Filter +
'(MedewerkerID = ''' + IntToStr(tmp.MedewerkerID) + ''' AND ' +
'OnderdeelID = ''' + IntToStr(tmp.OnderdeelID) + ''' AND ' +
'SUBLEVEL = ''' + IntToStr(3) + ''' ) OR ';
end;
end;
//Remove last or
Delete(Filter, Filter.Length - 2, 3);
GridPlanning.DataSource.DataSet.Filter := Filter;
GridPlanning.DataSource.DataSet.Filtered := True;
end;
Hope this would be usefull to someone.