2009-12-14 3 views
2

Ну, моя проблема заключается в следующем:Delphi - создание элементов управления до создания формы?

У меня есть Delphi 5 приложение, которое я по существу портирование на Delphi 2010 (замена старых компонентов с их последними версиями, фиксируя неизбежные проблемы строки Анси/Unicode, и т.д.) и я столкнулся с проблемой.

При создании одной из наших форм происходит нарушение прав доступа. Рассмотрев это, я пришел к выводу, что причина этого в том, что один из создателей, вызываемых в Create, пытается изменить свойство объекта в форме, которая еще не была создана.

Я обрезается его немного вниз, но код в основном выглядит следующим образом:

В форме декларации:

property EnGrpSndOption:boolean read fEnGrpSndOption write SetGrpSndOption; 

В форме Создать:

EnGrpSndOption := false; 

В реализации:

procedure Myform.SetGrpSndOption(const Value: boolean); 
begin 
    fEnGrpSndOption := Value; 
    btGrpSnd.Visible := Value; 
end; 

Перебрасывая в ShowMessage (BooltoStr (Assigned (btGrpSend), true)) прямо перед btGrpSnd.Visible: = Значение, я подтвердил, что проблема в том, что btGrpSnd еще не создан.

btGrpSend - это LMDButton, но я уверен, что он не совсем уместен, поскольку он еще не создан.

Хотя я понимаю, что, вероятно, мне нужно присвоить значение только после подтверждения того, что элемент управления назначен, это просто приведет к тому, что значение, установленное в create, не будет установлено на фактический элемент управления.

Так что я хочу, чтобы найти способ убедиться, что все элементы управления в форме созданы до того, как мой Create запущен.

Любая помощь в этом, или информация о том, как Delphi создает формы, будут оценены. Он работал в Delphi 5, поэтому я предполагаю, что причина этого должна быть упомянута где-то среди списков изменений между версиями. В конце концов, Delphi 2010 немного отличается от Delphi 5.

+0

Забыл отметить это: Я получаю нарушение прав доступа при размещении компонента в моей форме во время разработки. Возможно, это произойдет и во время выполнения, но я не могу подтвердить это, так как я не могу запустить его. –

+0

Добро пожаловать в Stack Overflow, Michael. :) –

+0

Спасибо ^^ Оглядываясь по сайту на другие проблемы, связанные с delphi, у меня тоже было, но я обычно обнаружил, что большинство из них были заданы и уже где-то отвечали;) –

ответ

0

Я вижу две возможности: проверьте, нет ли btGrpSnd, перед присвоением значения видимому свойству. Если это ноль, вы можете либо:

  • не установить свойство
  • СОЗДАТЬ btGrpSnd

я бы не стал возиться с порядком создания. Это сложнее и может прерваться с дальнейшими изменениями.


из вашего комментария: вы можете проверить, находитесь ли вы в дизайне или в режиме исполнения. Перед установкой видимости убедитесь, что вы находитесь в режиме разработки.

if not (csDesigning in Componentstate) then 
begin 
    btGrpSnd:=Value; 
end; 

Ответ на ваш комментарий:

пойти на это:

procedure Myform.SetGrpSndOption(const Value: boolean); 
begin 
    fEnGrpSndOption := Value; 
    if btGrpSnd<>nil then btGrpSnd.Visible := Value; 
end; 

и один дополнительный свойство настройки btGrpSnd. Если установлено значение <> nil, установите видимость в fEnGrpSndOption.

Если нет необходимости устанавливать btGrpSnd вне Myform, создайте процедуру init, которая создаст все. Например:

constructor Myform.Create(...) 
begin 
    init; 
end; 

procedure init 
begin 
    btGrpSnd:=TButton.Create; 
    ... 
end; 

procedure Myform.SetGrpSndOption(const Value: boolean); 
begin 
fEnGrpSndOption := Value; 
if btGrpSnd<>nil then init; 
btGrpSnd.Visible := Value; 
end; 

Это все же лучше, чем в зависимости от измененного кода инициализации, который может сломаться в будущем.

+0

Нам нужно, чтобы эти вещи выполнялись во время разработки. Например, свойство, указанное в моем вопросе, должно быть установлено во время разработки. –

3

Как упоминал Тобиас (но защищает против), вы можете изменить порядок создания (прямо в форме при изменении порядка создания).

Но вы также можете в методе setter проверить, создается ли форма (csCreating in form.componentstate). И если вам нужно сохранить это свойство самостоятельно и обрабатывать его в AfterConstruction.

+0

Я рассмотрю AfterConstruction. Но если есть такая вещь, разве почти всегда безопаснее использовать AfterConstruction вместо Create, когда вы пишете компонент, на котором есть элементы управления? –

2

Из вашего комментария, что вы получаете AV при размещении его во время разработки, это означает, что есть проблема с самим элементом управления, и он не был правильно перенесен вперед. Чтобы воспроизвести его во время выполнения в контролируемых условиях, вам нужно написать небольшую программу следующим образом:

Сделайте новое приложение VCL с одной формой. Поместите TButton в форму. На OnClick данной кнопки, сделать что-то вроде этого:

var 
    newButton: TLMDButton; 
begin 
    newButton := TLMDButton.Create(self); 
    newButton.Parent := self; 
    //assign any other properties you'd like here 
end; 

Поставьте точку останова на конструкторе и проследить в ней, пока вы не можете найти то, что вызывает нарушение прав доступа.

EDIT: Хорошо, посмотрев комментарии, я думаю, мы нашли вашу проблему!

Субконтролирование формы инициализируется путем чтения файла DFM. Когда вы изменили свой контроль на TCustomForm, вы предоставили новый DFM для его определения? Если нет, вам необходимо переопределить конструктор формы и создать элементы управления и определить их свойства вручную. Там нет «магии», которая инициализирует его для вас.

+0

Я сделал это сейчас, и это привело меня к той же строке кода, которую я нашел, посмотрев сообщение о нарушении прав доступа, данное мне во время разработки. Возможно, это то же самое, что я описываю в своем первоначальном вопросе, поскольку эта строка кода является той, где происходит нарушение прав доступа. Таким образом, это означает, что это происходит как при проектировании, так и во времени выполнения. Любая идея, почему элементы управления на компоненте, который я размещаю, не создаются до того, как создается компонент, когда он, по-видимому, вернулся в Delphi 5? –

+0

Опять же, забыли сказать: В любом случае, это могучий удобный трюк, который я обязательно передам в память. Я удивлен, что уже не думал об этом. Спасибо :) –

+0

Он должен быть создан. Если вы проверите, все остальные объекты в форме уже будут созданы к тому времени. Может быть, что-то не так, при десериализации компонента? Трудно сказать без дополнительной информации.BTW - это кнопка непосредственно в вашей форме, или это подкомпонент большего компонента, который вы разместили в своей форме? –

0

Является ли это достаточно хорошо, чтобы вы собираетесь:

если Assigned (btGrpSnd) и btGrpSnd.HandleAllocated затем btGrpSnd.Visible: = ...

+0

Ну, проблема в том, что это оставит значения неизменными, удалив точку их установки в Create в первую очередь. Кто-то уже предложил использовать AfterConstruction для назначения значений, которые не могут быть назначены во время Create, но я еще не потратил на это времени, потому что я действительно не хочу обходить проблему. Плюс Мне очень любопытно, как аспект автоматического создания delphi обрабатывает элементы управления формами. Не смогли найти ничего конкретного. Таким образом, я мог бы обойти это так, как вы это делаете, но я бы очень не хотел. Спасибо за это. –

1

Ваш Create всегда называется первой, перед предком конструктор. Вот как работают конструкторы. Вы должны быть в состоянии вызвать унаследованный конструктор, прежде чем сделать остальную часть вашей инициализации:

constructor MyForm.Create(Owner: TComponent); 
begin 
    inherited; 
    EnGrpSndOption := False; 
end; 

Однако есть лучший способ указания того, что вы пытаетесь сделать случиться. Ваш класс загружает свойства из ресурса DFM. Когда он будет завершен, он вызовет виртуальный метод с именем Loaded. Обычно он используется для уведомления всех детей о том, что все готово, поэтому, если какой-либо из них содержит ссылки на других детей в форме, они знают, что безопасно использовать эти ссылки в этот момент.Вы также можете переопределить его в форме.

procedure MyForm.Loaded; 
begin 
    inherited; 
    EnGrpSndOption := False; 
end; 

В общем случае это не должно иметь большого значения в вашем случае. Loaded вызывается из конструктора сразу после того, как форма заканчивает загрузку из ресурса DFM. Этот ресурс сообщает форме все элементы управления, которые он должен создать для себя. Если ваша кнопка не создается, она, вероятно, неправильно указана в DFM. Возможно, что элементы управления будут перечислены в DFM, которые не имеют соответствующих полей в классе. С другой стороны, если есть опубликованное поле, в котором нет соответствующей записи в DFM, среда IDE должна предупредить вас об этом и предложить удалить декларацию каждый раз, когда вы ее создадите в конструкторе форм. Просмотрите свой DFM как текст и подтвердите, что есть действительно запись для элемента управления с именем btGrpSnd.

+0

Ну, там, к сожалению, есть такие записи. Если DFM содержит данные, полностью скрытые от кодера, которые также должны быть правильными, это, похоже, не является проблемой. Здесь нужно надеяться, что новый DFM может решить это ... Благодарим вас за описание Loaded. Я определенно хотел знать, существует ли такая процедура. –

Смежные вопросы