Почему я получаю нарушение прав доступа при доступе к TValueListEditor, найденному с помощью FindControl? - PullRequest
1 голос
/ 13 июня 2011

Я динамически создал TValueListEditor компонент VCL на TForm. Код находится во вложенной процедуре одного из основных методов формы. Я установил:

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 ]

1 голос
/ 14 июня 2011

Если ваша динамически созданная форма является частью того же приложения, вам не нужен весь шум неправильного 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;
1 голос
/ 14 июня 2011

Как прокомментировал Кен, ваша проблема заключается в том, что вместо поиска редактора списка значений вы находите свою форму и затем настраиваете ее тип в редакторе списка значений, отсюда и 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
    ...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...