I have created two general use frames; one for a grid and one for a single record CRUD.
The two frames work hand in hand where I assign values to the grid frame properties and it's smart enough to get the data for the grid, create the desired columns with headings and provide navigation and single record CRUD when one of the CRUD events is fired. The grid frame includes a property for setting the CRUD frame (TframeBaseEdit).
Basically, by assigning the appropriate CRUD frame to the Grid frame, we have a reusable method of grid display + CRUD.
Currently I am using a separate strongly typed array to maintain the list of "live" frames, separated by type:
TframeBase = class(TIWFrame)
TframeEditBase = class(TframeBase)
TframeGridBase = class(TframeBase)
FframeArray: Array of TIWFrame;
FframeBaseArray: Array of TframeBase;
FframeEditBaseArray: Array of TframeEditBase;
FframeGridBaseArray: Array of TframeGridBase;
Currently...when I create the various frames, I insert them into the appropriate array, based on the frame type.
I make sure that all of the frames are invisible and have no daddy. This is one example where I have 4 separate arrays, each of a type that is descended from the previous. A single array of type ??? would help. Or, should I create an array of pointers and assign the frames to the array by reference?
Code:
for i := 0 to iFrameCount - 1 do
begin
if Assigned(Self.FframeArray[i]) then
begin
(Self.FframeArray[i] as TIWFrame).Visible := False;
(Self.FframeArray[i] as TIWFrame).Parent := nil;
end;
if Assigned(Self.FframeBaseArray[i]) then
begin
Self.FframeBaseArray[i].Visible := False;
Self.FframeBaseArray[i].Parent := nil;
end;
if Assigned(Self.FframeGridBaseArray[i]) then
begin
Self.FframeGridBaseArray[i].Visible := False;
Self.FframeGridBaseArray[i].Parent := nil;
end;
if Assigned(Self.FframeEditBaseArray[i]) then
begin
Self.FframeEditBaseArray[i].Visible := False;
Self.FframeEditBaseArray[i].Parent := nil;
end;
end;
This code is showing where I initialize the frame (the end result of .Initialize is that the frame is rendered). Clearly this would be better with a single array rather than an array for each type of frame.
Code:
if Assigned(Self.FframeArray[iFrame]) then
begin
SetFrameParent(Self.FframeArray[iFrame], Self.regionMain);
end;
if Assigned(Self.FframeBaseArray[iFrame]) then
begin
SetFrameParent(Self.FframeBaseArray[iFrame], Self.regionMain);
Self.FframeBaseArray[iFrame].Initialize;
end;
if Assigned(Self.FframeGridBaseArray[iFrame]) then
begin
SetFrameParent(Self.FframeGridBaseArray[iFrame], Self.regionMain);
Self.FframeGridBaseArray[iFrame].Initialize;
end;
if Assigned(Self.FframeEditBaseArray[iFrame]) then
begin
SetFrameParent(Self.FframeEditBaseArray[iFrame], Self.regionMain);
Self.FframeEditBaseArray[iFrame].Initialize;
end;
Here is some of the code where I'm creating the various regular frames, grid frames and their CRUD frames:
Code:
SetLength(Self.FframeGridBaseArray, iFrameCount);
SetLength(Self.FframeEditBaseArray, iFrameCount);
SetLength(Self.FframeBaseArray, iFrameCount);
SetLength(Self.FframeArray, iFrameCount);
for i := 0 to iFrameCount - 1 do
begin
begin
if (i = Ord(TApplicationFrames.afInvalidClientIPAddress)) then
begin
Self.FframeInvalidClientIPAddress := TframeInvalidClientIPAddress.Create(Self);
Self.FframeInvalidClientIPAddress.Name := Include.C_FRAME_INVALIDCLIENTIPADDRESS;
Self.FframeInvalidClientIPAddress.Request := Webapplication.Request;
end
else if (i = Ord(TApplicationFrames.afLogin)) then
begin
Self.FframeLogin := TframeLogin.Create(Self);
Self.FframeLogin.Name := Include.C_FRAME_LOGIN;
Self.FframeLogin.DefaultFrameName := Include.C_FRAME_MAIN;
end
else if (i = Ord(TApplicationFrames.afMain)) then
begin
Self.FframeArray[i] := TframeMain.Create(Self);
Self.FframeArray[i].Name := Include.C_FRAME_MAIN;
(Self.FframeArray[i] as TframeMain).LockIndicator := Self.IWCGJQLockIndicator1;
end
else if (i = Ord(TApplicationFrames.afPreferencesCompany)) then
begin
Self.FframeEditBaseArray[i] := TframeEditPreferencesCompany.Create(Self);
Self.FframeEditBaseArray[i].Name := Include.C_FRAME_EDIT_PREFERENCES_COMPANY;
end
else if (i = Ord(TApplicationFrames.afUsersList)) then
begin
Self.FframeGridBaseArray[i] := TframeGridBase.Create(Self);
Self.FframeGridBaseArray[i].Name := Include.C_FRAME_GRID_USERS;
Self.FframeGridBaseArray[i].ViewData := Include.C_VIEW_DATA_LIST_USERS;
Self.FframeGridBaseArray[i].EditFrame := TframeEditUser.Create(Self);
Self.FframeGridBaseArray[i].EditFrame.Name := Include.C_FRAME_EDIT_USER;
// Frame.UnInitialize will call EditFrame.RefreshGridProc if we assign it
Self.FframeGridBaseArray[i].EditFrame.RefreshGridProc := Self.FframeGridBaseArray[i].RefreshGridData;
// Assign EditFrame.EditData procedure to GridFrame.EditProc so that when you select a row it will display the EditFrame
Self.FframeGridBaseArray[i].EditProc := (Self.FframeGridBaseArray[i].EditFrame as TframeEditUser).EditData;
end
else if (i = Ord(TApplicationFrames.afSecurityProfileList)) then
begin
Self.FframeGridBaseArray[i] := TframeGridBase.Create(Self);
Self.FframeGridBaseArray[i].Name := Include.C_FRAME_GRID_SECURITY_PROFILES;
Self.FframeGridBaseArray[i].ViewData := Include.C_VIEW_DATA_LIST_SECURITY_PROFILES;
Self.FframeGridBaseArray[i].EditFrame := TframeEditSecurityProfile.Create(Self);
Self.FframeGridBaseArray[i].EditFrame.Name := Include.C_FRAME_EDIT_SECURITY_PROFILE;
// Frame.UnInitialize will call EditFrame.RefreshGridProc if we assign it
Self.FframeGridBaseArray[i].EditFrame.RefreshGridProc := Self.FframeGridBaseArray[i].RefreshGridData;
// Assign EditFrame.EditData procedure to GridFrame.EditProc so that when you select a row it will display the EditFrame
Self.FframeGridBaseArray[i].EditProc := (Self.FframeGridBaseArray[i].EditFrame as TframeEditSecurityProfile).EditData;
end
else if (i = Ord(TApplicationFrames.afEditPassword)) then
begin
end
else if (i = Ord(TApplicationFrames.afExportData)) then
begin
Self.FframeArray[i] := TframeExportData.Create(Self);
Self.FframeArray[i].Name := Include.C_FRAME_EXPORT_DATA;
(Self.FframeArray[i] as TframeExportData).LockIndicator := Self.IWCGJQLockIndicator1;
end;
end;
if Assigned(Self.FframeArray[i]) then
begin
Self.FframeArray[i].Parent := nil;
Self.FframeArray[i].Visible := False;
Self.FframeArray[i].Height := Self.regionMain.Height;
Self.FframeArray[i].Width := Self.regionMain.Width;
Self.FframeArray[i].Align := TAlign.alClient;
end;
if Assigned(Self.FframeBaseArray[i]) then
begin
Self.FframeBaseArray[i].Parent := nil;
Self.FframeBaseArray[i].Visible := False;
Self.FframeBaseArray[i].Height := Self.regionMain.Height;
Self.FframeBaseArray[i].Width := Self.regionMain.Width;
Self.FframeBaseArray[i].Align := TAlign.alClient;
Self.FframeBaseArray[i].LockIndicator := Self.IWCGJQLockIndicator1;
end;
if Assigned(Self.FframeGridBaseArray[i]) then
begin
Self.FframeGridBaseArray[i].Parent := nil;
Self.FframeGridBaseArray[i].Visible := False;
Self.FframeGridBaseArray[i].Height := Self.regionMain.Height;
Self.FframeGridBaseArray[i].Width := Self.regionMain.Width;
Self.FframeGridBaseArray[i].Align := TAlign.alClient;
Self.FframeGridBaseArray[i].LockIndicator := Self.IWCGJQLockIndicator1;
end;
The short of it is this: How do I maintain a single list of these various frame types?
Array of objects?
Array of pointers?
Crayola and Big Chief Pad?
I appreciate y'all letting me have a few spin cycles from your personal beanie propeller to help me figure this out.
Thanks,
Scott
(05-04-2018, 04:51 PM)DanBarclay Wrote: [ -> ]What was the complaint, and when (runtime/designtime)?
Did it sound like a name collision or something?
Dan
myFrames: Array of TframeBase;
...
myFrames[i] := TframeGridBase.Create(Self); // << This assignment does not throw an exception, but the parent type (TframeBase) causes me to lose the added functionality in TframeGridBase