简体   繁体   中英

Access Violation when handling forms

I have procedure to show/hide one element on TForm like that:

procedure ShowHideControl(const ParentForm: TForm; const ControlName: String; ShowControl: Boolean);
var
  i: Integer;
begin
  for i := 0 to pred(ParentForm.ComponentCount) do
  begin
    if (ParentForm.Components[i].Name = ControlName) then
    begin
      if ShowControl then
        TControl(ParentForm.Components[i]).Show
      else
        TControl(ParentForm.Components[i]).Hide;

      Break;
    end;
  end;
end;

then I try to use it like:

procedure TForm1.Button6Click(Sender: TObject);
begin
  ShowHideEveryControl(TForm(TForm1), 'Button4', True);
end;

Why do I get Access Violation on Button6 click?

For me everything is OK... Button4 exists as a child :)

This cast is wrong:

TForm(TForm1)

You are telling the compiler to ignore the fact that TForm1 is not a TForm instance, and asking it to pretend that it is. That is fine until you actually try to use it as an instance, and then the error occurs.

You need to pass a real instance to a TForm descendent. You can write it like this:

ShowHideEveryThing(Self, 'Button4', True);

Just in case you are not clear on this, the parameter of your procedure is of type TForm . That means you need to supply an instance of a class that either is, or derives from TForm . I repeat, you must supply an instance. But you supply TForm1 which is a class .


And then the next problem comes here:

if (ParentForm.Components[i].Name = FormName) then
begin
  if ShowForm then
    TForm(ParentForm.Components[i]).Show
  else
    TForm(ParentForm.Components[i]).Hide;

  Break;
end;

Again you have used an erroneous cast. When the compiler tells you that it a particular object does not have a method, you must listen to it. It's no good telling the compiler to shut up and pretend that an object of one type is really an object of a different type. Your button is categorically not a form, so don't try to cast it to TForm .

It is very hard to know what you are actually trying to do here. When you write:

ShowHideEveryThing(Self, 'Button4', True);

It would seem to me to me more sensible to write:

Button4.Show;

It is not a good idea to refer to controls using their names represented as text. It is much safer and cleaner to refer to them using reference variables. That way you let the compiler do its job and check the type safety of your program.


The names used in your function are suspect:

procedure ShowHideEveryThing(const ParentForm: TForm; const FormName: String; 
  ShowForm: Boolean);

Let's look at them:

  • ShowHideEveryThing : but you claim that the function should show/hide one element. That does not tally with the use of everything .
  • FormName : you actually pass a component name, and then look for components owned by ParentForm that have that name. It seems that FormName is wrong.
  • ShowForm : again, do you want to control visibility of the form, or a single element?

Clearly you need to step back and be clear on the intent of this function.


As an aside, you should generally never need to write:

if b then
  Control.Show
else
  Control.Hide;

Instead you can write:

Control.Visible := b;

My number one piece of advice to you though is to stop casting until you understand it properly. Once you understand it properly, design your code if at all possible so that you don't need to cast. If you ever really do need to cast, make sure that your cast is valid, ideally by using a checked cast with the as operator. Or at least testing first with the is operator.

Your code shows all the hallmarks of a classic mistake. The compiler objects to the code that you write. You have learnt from somewhere that casting can be used to suppress these compiler errors and now you apply this technique widely as a means to make your program compile. The problem is that the compiler invariably knows what it is talking about. When it objects, listen to it. If ever you find yourself suppressing a compiler error with a cast, take a step back and think carefully about what you are doing. The compiler is your friend.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM