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

发布于 2024-11-15 05:50:38 字数 1920 浏览 1 评论 0原文

我在 TForm 上动态创建了 TValueListEditor 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;

我尝试了各种类型转换、值、参数......没有任何效果。

我的错误是什么?

我正在使用德尔福XE。

I have dynamically created TValueListEditor VCL component on a TForm. The code is located in nested procedure of one of the main form's methods. I have set:

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

It looks like this:

TMainForm.Method();

Method has a nested procedure that contains code that creates the components mentioned above.

Then, I have helper function:

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

In this helper I use this code to load an XML file and then retrieve its nodes and insert them into 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;

The problem is that I get access violations every time code goes into the line:

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

I have tried various typecasts, values, parameters .. nothing does the trick.

What is my mistake?

I'm using Delphi XE.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

枫以 2024-11-22 05:50:38

正如 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
    ...

As Ken commented your problem is, instead of finding the value list editor, you are finding your form and then typecasting it to a value list editor, hence the AV.

First, you're passing 'TForm' as 'lpClassName' to FindWindow. Assuming 'TForm' is the class name of your form, it will of course find the form - not a child window on it. Second, you cannot use FindWindow to find a child window, see its documentation, it searches top-level windows.

If you had tested the return of FindControl, the code raising the AV would never run:

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

You can use FindWindowEx to search in child windows, if you don't know the handle of your form find it first as you've done already:

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

or better yet, test the return of FindWindowEx first to avoid passing '0' to FindControl:

ValueListEditorHandle := FindWindowEx(FormHandle, 0, 'TValueListEditor', nil);
if Win32Check(ValueListEditorHandle <> 0) then
begin
  Control := FindControl(ValueListEditorHandle);
  if Assigned(Control) then
  begin
    ...
落在眉间の轻吻 2024-11-22 05:50:38

如果您动态创建的表单是同一应用程序的一部分,则您不需要错误 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;

If your dynamically created form is part of the same application, you don't need all the noise of the incorrect FindControl(FindWindow()). Just create your form, giving it a name, and making Application the owner:

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

When you want to get a new reference to it:

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 can now access the TValueListEditor directly:

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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文