当我访问使用FindControl找到的TValueListEditor时,为什么会出现访问冲突?

时间:2011-06-13 17:02:44

标签: delphi findcontrol

我在TValueListEditor上动态创建了TForm VCL组件。代码位于主窗体方法之一的嵌套过程中。我已经设定了:

ValueListEditor.KeyOptions := [keyEdit, keyAdd, keyUnique];

看起来像这样:

TMainForm.Method();

Method有一个嵌套过程,其中包含用于创建上述组件的代码。

然后,我有辅助功能:

function GetMenuListData(XMLNode: TXMLNode; const XNMLDoc: string = '') : string;

在这个帮助器中,我使用此代码加载XML文件,然后检索其节点并将其插入ValueListEditor

XMLDoc := TXMLDocument.Create(Self);
XMLDoc.ParseOptions := [poPreserveWhiteSpace];
try
  XMLDoc.LoadFromFile(XNMLDoc);
  try
    Control := FindControl(FindWindow('TForm',PChar('(' + ExtractFileExt(Form1.Edit1.Text) + ')')));
    if Control <> nil then
    begin
      TValuelistEditor(Control).Keys[TValuelistEditor(Control).RowCount-1] := XMLDoc.DocumentElement.NodeName;
      if XMLDoc.DocumentElement.ChildNodes.First.AttributeNodes.Count > 0 then
        TValuelistEditor(Control).Values[TValuelistEditor(Control).Keys[TValuelistEditor(Control).RowCount-1]] := String(XMLDoc.DocumentElement.Attributes['id'])
      else
        TValuelistEditor(Control).Values[TValuelistEditor(Control).Keys[TValuelistEditor(Control).RowCount-1]] := '<Empty>';
    end else begin
      MessageBeep(0);
      FlashWindow(Application.Handle, True);
      ShowMessagePos('...');
    end;
  finally
    XMLDoc.Active := False; Result := 'Forced ' + Form1.RAWInputBtn.Caption + ' in ' + DateTimeToStr(Now);
  end;
except
  on E : EXMLDocError do
  begin
    Result := 'Forced ' + Form1.RAWInputBtn.Caption + ' in ' + DateTimeToStr(Now);
  end;
end;

问题在于,每次代码进入该行时,我都会遇到访问冲突:

TValuelistEditor(Control).Keys[TValuelistEditor(Control).RowCount-1] := XMLDoc.DocumentElement.NodeName;

我尝试了各种类型转换,值,参数......没有什么可行的。

我的错误是什么?

我正在使用Delphi XE。

2 个答案:

答案 0 :(得分:1)

正如Ken所说,你的问题是找到你的表单,然后将其类型转换为值列表编辑器,而不是找到值列表编辑器,而不是找到它。这就是AV。

首先,您将'TForm'作为'lpClassName'传递给FindWindow。假设'TForm'是表单的类名,它当然会找到表单 - 而不是它上面的子窗口。其次,您无法使用FindWindow查找子窗口,查看其文档,它会搜索顶级窗口。

如果您测试了FindControl的返回值,则提升AV的代码将永远无法运行:

  if (Control <> nil) and (Control is TValueListEditor) then


您可以使用FindWindowEx在子窗口中进行搜索,如果您不知道表单的句柄,请先找到它:

FormHandle := FindWindow('TForm',PChar('(' + ExtractFileExt(Form1.Edit1.Text) + ')'));
if FormHandle <> 0 then
begin
  Control := FindControl(FindWindowEx(FormHandle, 0, 'TValueListEditor', nil));

或者更好的是,首先测试FindWindowEx的返回值,以避免将'0'传递给FindControl

ValueListEditorHandle := FindWindowEx(FormHandle, 0, 'TValueListEditor', nil);
if Win32Check(ValueListEditorHandle <> 0) then
begin
  Control := FindControl(ValueListEditorHandle);
  if Assigned(Control) then
  begin
    ...

答案 1 :(得分:1)

如果动态创建的表单是同一个应用程序的一部分,则不需要所有错误的FindControl(FindWindow())。只需创建表单,为其命名,然后将Application设为所有者:

MyForm := TMyForm.Create(Application);
MyForm.Name := 'MyDynamicForm';

如果您想获得新的参考资料:

var
  TheForm: TMyForm;
  i: Integer;
begin
  TheForm := nil;
  for i := 0 to Screen.FormCount - 1 do
    if Screen.Forms[i] is TMyForm then
      // Could also use Screen.Forms[i].Caption
      if Screen.Forms[i].Name = 'MyDynamicForm' then
        TheForm := TMyForm(Screen.Forms[i]);

  if Assigned(TheForm) then
    TheForm.MethodThatLoadsXML(XMLFileName); // or whatever
end;

TheForm.MethodThatLoadsXML现在可以直接访问TValueListEditor

procedure TMyForm.MethodThatLoadsXML(const XMLFileName: string);
begin
  // Load xml as before, using XMLFileName
  with TValueListEditor.Create(Self) do
  begin
    Options := [Whatever];
    Parent := Self;
    Left := SomeNumber;
    Top := SomeNumber;
    // Create items for value list from XML and other stuff
  end;
end;