Reputation: 71
I am trying to free a component when closing a form but when i run this code I keep getting "Invalid class typecast" error and I don't know why.
procedure TfrmMenu.FormHide(Sender: TObject);
var
I: Integer;
sID: String;
begin
I := 0;
repeat
Inc(I);
with dmMenu.qryMcDonalds do
begin
SQL.Text := 'Select ItemID FROM tblMenu WHERE ItemID LIKE "' + IntToStr
(I) + '%"';
Open;
end;
sID := dmMenu.qryMcDonalds.Fields[0].AsString;
if (Components[I] as TImage).Name = 'imgd' + sID then
begin (Components[I] as TImage)
.Free;
end;
if (Components[I] as TLabel).Name = 'lbld' + sID then
begin (Components[I] as TLabel)
.Free;
end;
until I = ComponentCount - 1;
end;
Upvotes: 3
Views: 7856
Reputation: 84550
Your problem is in this part:
if (Components[I] as TImage).Name = 'imgd' + sID then
begin (Components[I] as TImage)
.Free;
end;
if (Components[I] as TLabel).Name = 'lbld' + sID then
begin (Components[I] as TLabel)
.Free;
end;
An as
cast in Delphi is basically an assertion cast: you're saying that you're sure it will be that type, and if it's not, to raise an invalid cast exception. Right now, you're asserting that every single component will be both a TImage
and a TLabel
, which obviously will never be true.
What you probably really want to do is this:
if (Components[I] is TImage) and (Components[I].Name = 'imgd' + sID) then
begin
Components[I].Free;
end;
if (Components[I] is TLabel) and (Components[I].Name = 'lbld' + sID) then
begin
Components[I].Free;
end;
You don't actually need the casts in there, since Name
is a property on the TComponent
base class.
EDIT: A few points as noted by Andreas in the comments:
First, if you're iterating over a collection and removing items from it, you need to work backwards. To illustrate why, let's remove all even numbers from this list:
[1, 3, 5, 2, 4, 6]
So if we do something like this:
for i := 0 to list.Length - 1 do
begin
if list[i] mod 2 = 0 then
begin
list.Remove(i);
end;
end;
On the first three iteration, we find numbers that are not even. So far so good. But on #4, (i = 3), we have an even number. We remove it from the list. The list is now [1, 3, 5, 4, 6]
. Now we increment i
to 4. Element #4 in this new list is the 6; we've skipped the 4! This only works if you're counting backwards, because then deleting things only rearranges the work you've already done, not the work you still have left to do.
Also, the Components
collection on the form will contain all of your components, in whatever order they were set up in the form designer. It's not particularly likely that whatever image you called imgd1
will be component #1 in that collection. If you're looking for any components of those types with a name starting with imgd
or lbld
followed by a number, you'll probably want to write a custom name validation function that checks for that. But checking if the number is the same as I
is more or less useless as I
is completely arbitrary here.
Upvotes: 4