Daryl990
Daryl990

Reputation: 11

FindComponent Not Finding Components Created at Runtime

I use Delphi 7 with a number of third party components. My main stub application loads a number of DLLs, which are various modules like creditors, debtors, purchase orders, and so on.

I have an issue with FindComponent(). 99% of the time, it works how it should. But not for the code below.

I was trying to create a form reports, where I keep all the details of the reports selection criteria in a table, and then create the criteria on the fly. In theory, it should work perfectly, but for some reason after creating the components, FindComponent() cannot find them.

try
  for i := gbSelectionCriteria.ComponentCount - 1 downto 0 do begin
    ShowMessage(gbSelectionCriteria.Components[i].Name);
    gbSelectionCriteria.Components[i].Free;
  end;

  // The above loop to remove the components from the groupbox works fine

  // Creating the components works

  fSysData.tbSelectionCriteria.First;
  while not fSysData.tbSelectionCriteria.EOF do begin
    case fSysData.tbSelectionCriteriaComponentType.AsInteger of
      1 : begin  // TMyAdvEdit
        with TMyAdvEdit.Create(gbSelectionCriteria) do begin
          Visible := False;
          Parent := gbSelectionCriteria;
          Name := fSysData.tbSelectionCriteriaName.AsString;
          Left := fSysData.tbSelectionCriteriaLeft.AsInteger;
          Top := fSysData.tbSelectionCriteriaTop.AsInteger;
          Width := fSysData.tbSelectionCriteriaWidth.AsInteger;
          LabelCaption := fSysData.tbSelectionCriteriaCaption.AsString;
          LabelPosition := AdvEdit.lpLeftCenter;
          LabelAlwaysEnabled := True;
          LabelTransparent := True;
          EditType :=  MyEditType[fSysData.tbSelectionCriteriaDataType.AsInteger];
          Text := '';

          OnClick := GetClickEvent(fSysData.tbSelectionCriteriaOnClickEvent.AsString);
          OnDblClick := GetClickEvent(fSysData.tbSelectionCriteriaOnDblClickEvent.AsString);
          OnKeyPress := GetKeyPressEvent(fSysData.tbSelectionCriteriaOnKeyPressEvent.AsString);

          Visible := True;

          // at this point findComponent finds nothing

          if FindComponent(Name) <> nil then
            ShowMessage(Name+' Created');
        end;

        edEdit.OnClick := GetClickEvent(fSysData.tbSelectionCriteriaOnClickEvent.AsString);
        edEdit.OnDblClick := GetClickEvent(fSysData.tbSelectionCriteriaOnDblClickEvent.AsString);
        edEdit.OnKeyPress := GetKeyPressEvent(fSysData.tbSelectionCriteriaOnKeyPressEvent.AsString);
        edEdit.Visible := True;

        if FindComponent(edEdit.Name) <> nil then
          ShowMessage(edEdit.Name+' Created');

      end;

      2 : begin
      end;

      3 : begin
      end;

      4 : begin
      end;

      5 : begin
      end;

      6 : begin
      end;

      7 : begin
      end;

      8 : begin
      end;
    end;

    fSysData.tbSelectionCriteria.Next;
  end;

  if fSysData.tbSysReports.Locate('ReportID', TAdvOfficeRadioButton(Sender).Tag, []) then begin
    ReportData.ReportID := TAdvOfficeRadioButton(Sender).Tag;
    ReportData.RepName := fSysData.tbSysReportsReportName.AsString;
    ReportData.RepTitle := fSysData.tbSysReportsReportTitle.AsString;
    ReportData.RepModule := fSysData.tbSysReportsModule.AsString;
    ReportData.RepOrientation := fSysData.tbSysReportsReportOrientaton.AsString;
    ReportData.RepPageIndex := fSysData.tbSysReportsCriteriaPageIndex.AsInteger;
  end;
finally
end;

The Process of the reports is:

  1. User clicks a button

  2. Radio buttons are created from the button click

  3. User clicks a radio button

  4. Report criteria is created from the radio button click

  5. User enters data or DblClicks to select data from a list.

  6. User Clicks Preview button to view Report - this is where FindComponent fails and returns nil..

All the code worked before when I had created all the criteria at design time, then added the code above.

The code below is part of what needs to be added to the query to retrieve the data for the report:

if Length(TMyAdvEdit(FindComponent('edQuoteReference')).Text) > 0 then
  qryTempTable.SQL.Add('  and q.UserReference = "' + TMyAdvEdit(FindComponent('edQuoteReference')).Text + '"');

This is the first time FindComponent() fails and goes no further.

I have tried various ways to create the components, but each of them results in an Access Violation because the component is nil.

I have looked everywhere, and tried everything I can think of, for a solution to this problem.

Upvotes: 0

Views: 4463

Answers (2)

Daryl990
Daryl990

Reputation: 11

Firstly I do apologize if this is in the wrong spot..

Thanks for the response and the answer, I have been doing this for a lot of years and I can't believe I missed something so small.

this, if FindComponent(Name) <> nil then

should have been this, if gbSelectionCriteria.FindComponent(Name) <> nil then

I don't normally use with, it was just one way to test create the component. I set the components visibility to false before and then to true after it is created to stop flicker as it creates.

Thanks again..

Upvotes: 1

David Heffernan
David Heffernan

Reputation: 612894

FindComponent searches for components owned by the subject of the method call. You call FindComponent on the form, and so look for the component amongst those components owned by the form. But the control you search for is not owned by the form, it is owned by gbSelectionCriteria, which is what you passed to the control's constructor as the Owner argument.

If you wish to use FindComponent in the way you do you therefore need to make the form be the owner of the controls that you create. Then when you call FindComponent on the form, it can find the control because it is the owner. Pass Self to the control's constructor to make this come to pass:

TMyAdvEdit.Create(Self)

I'm having to make some reasonably large guesses here. Perhaps this code actually resides in a data module rather than a form. But the essential principle will be as I say.

Upvotes: 8

Related Questions