2
votes

I have several TEdit boxes on my form. The data is tied to hardware that has the same min and max values for each range but several ranges. If the user updates the max value for any range by typing in the TEdit box, I want update the corresponding min box as well as a TEdit box that holds the product of the max times another value, etc. Since all the TEdit boxes have similar names, I would like to know if I can pass just the distinguishing string to a generic procedure and construct the name of the specific TEdit boxes to alter there. At run-time, I get "Access violation at address 0074CB11 in module 'MyProject.exe'. Read of address 8BD88B77." Any advice would be appreciated.

procedure TForm1.R1IMaxEditChange(Sender: TObject);
//User types a new Range 1 Maximum I value
begin
  UpdateIMin_Power('R1')
end;


procedure TForm1.UpdateIMin_Power(Range: string);
var
  R_IMax, R_IMin, R_Power, R_Volts: TEdit;
begin
  //Assign variable names to TEdit boxes already on form.
  R_IMax.Name := Range + 'IMaxEdit';  //'R1IMaxEdit' when called by R1IMaxEditChange
  R_Volts.Name := Range + 'VoltsEdit';
  R_IMin.Name := Range + 'IMinEdit';
  R_IPower.Name := Range + 'IPowerEdit';

  //IMax already manually entered by user in R1IMaxEdit; Volts already on form
  R_IMin.Text := R_IMax.Text;  //Let IMin = IMax
  R_Power.Text := FloatToStr(StrToFloat(R_IMax.Text) * StrToFloat(R_Volts.Text)); //Power = Imax * Voltage
end;
1

1 Answers

1
votes

You have four variables R_IMax, R_IMin, R_Power, R_Volts. You do not initialise these variables, but you then attempt to use methods and properties of them. That is an error.

You must assign object references before using them. You need code like this:

R_IMax := GetEditReferenceFromSomewhere(Range + 'IMaxEdit');

Obviously you need an implementation of GetEditReferenceFromSomewhere. Personally I would pass the four edit controls as parameters to the method:

procedure TForm1.UpdateIMin_Power(R_IMax, R_IMin, R_Power, R_Volts: TEdit);
begin
  //IMax already manually entered by user in R1IMaxEdit; Volts already on form
  R_IMin.Text := R_IMax.Text;  //Let IMin = IMax
  R_Power.Text := FloatToStr(StrToFloat(R_IMax.Text) * StrToFloat(R_Volts.Text)); //Power = Imax * Voltage
end;

If you want to treat these controls as a group, then create a record type to hold them:

type
  TEditControlGroup = record
    R_IMax: TEdit;
    R_IMin: TEdit;
    R_Power: TEdit;
    R_Volts: TEdit;
  end;

Declare and populate a bunch of these records when your form is created, and pass them to the method which now looks like this:

procedure TForm1.UpdateIMin_Power(const Controls: TEditControlGroup);
begin
  //IMax already manually entered by user in R1IMaxEdit; Volts already on form
  Controls.R_IMin.Text := Controls.R_IMax.Text;  //Let IMin = IMax
  Controls.R_Power.Text := FloatToStr(StrToFloat(Controls.R_IMax.Text) * StrToFloat(Controls.R_Volts.Text)); //Power = Imax * Voltage
end;

If you are simply desperate to use the control names then you could use FindComponent but I am simply loathe to recommend that.

procedure TForm1.UpdateIMin_Power(const Range: string);
var
  R_IMax, R_IMin, R_Power, R_Volts: TEdit;
begin
  //Assign variable names to TEdit boxes already on form.
  R_IMax := FindComponent(Range + 'IMaxEdit');  //'R1IMaxEdit' when called by R1IMaxEditChange
  R_Volts := FindComponent(Range + 'VoltsEdit');
  R_IMin := FindComponent(Range + 'IMinEdit');
  R_IPower := FindComponent(Range + 'IPowerEdit');

  //IMax already manually entered by user in R1IMaxEdit; Volts already on form
  R_IMin.Text := R_IMax.Text;  //Let IMin = IMax
  R_Power.Text := FloatToStr(StrToFloat(R_IMax.Text) * StrToFloat(R_Volts.Text)); //Power = Imax * Voltage
end;