-
При использовании в крите обращения к хэндлу компонента: inherited Create(AOwner);
DragAcceptFiles(Handle,True); возникает ошибка "control '' has no parent window"Как понимаю, она возникает из-за того, что Handle компонента еще не задан и процедура DragAcceptFiles прерывает проц. Create. Есть ли какие-нибудь методы обхода данной проблемки?
-
В общем случае, при выполнении конструктора окно еще не создано и, соответственно, свойство Handle еще не проинициализировано. Это произойдет после выполнения метода CreateWnd.
У некоторых контролов окно создается при первом обращении к Handle (даже если оно происходит и в конструкторе), но не у всех это так.
Отсюда вывод - надо заместить метод CreateWnd и код, которому нужен хэндл, перенести в него ПОСЛЕ вызова Inherited. Тогда всегда будем иметь правильный хэндл, даже и при пересоздании окна.
-
> Юрий Зотов © (11.06.07 12:37) [1]
Спасибо, разобрался, только теперь при закрытии программы возникает такая ошибка: "control 'ControlFiles1' has no parent window". Код дестуктора: destructor TControlFiles.Destroy;
begin
DragAcceptFiles(Handle,False); inherited Destroy;
end;
procedure TControlFiles.CreateWnd;
begin
inherited;
DragAcceptFiles(Handle,True); end; Убрав DragAcceptFiles(Handle,False) работает нормально, но все же желательно оставить. Да и разобратся почему возникает ошибка в CreateWnd при вызове destructor'а?!
-
Вообщем так работает: procedure TControlFiles.DestroyWnd;
begin
inherited;
DragAcceptFiles(Handle,False);
end; еще раз спасибо.
-
> Krants
Аналогично, когда отрабатывает деструктор, то окно УЖЕ уничтожено и поэтому обращение к Handle дает ошибку.
Перекрыть DestroyWnd - правильное решение, но строчки в нем, видимо, надо поменять местами. По логике, надо СНАЧАЛА разрегистрировать окно, как приемник операции "дрыг-н-прыг", а уж ПОТОМ вызывать inherited, чтобы это окно уничтожить.
-
> Юрий Зотов © (11.06.07 12:37) [1] > У некоторых контролов окно создается при первом обращении > к Handle (даже если оно происходит и в конструкторе), но > не у всех это так.
Не согласен, у всех оконных контролов создание окна происходит именно при обращении к Handle (точнее - при вызове HandleNeeded, который имеется в GetHandle), просто те окна, которые имеют стиль WS_CHILD, обязаны иметь окно-родителя, поэтому, если в момент обращения к Handle родитель ещё не назначен, VCL не может создать окно и выкидывает исключение... Нет таких контролов, у которых обращение к Handle допустимо после создания окна, но есть те, у которых оно допустимо только после назначения свойства Parent...
> Юрий Зотов © (11.06.07 14:19) [4] > Аналогично, когда отрабатывает деструктор, то окно УЖЕ уничтожено > и поэтому обращение к Handle дает ошибку.
Аналогично, ошибка возникает не из-за самого обращения к Handle, а из-за того, что HandleNeeded вызывает CreateHandle, а тот опять вызывает CreateWnd, а CreateWnd обламывается с повторным созданием окна, потому что там WS_CHILD, а Parent на этот момент уже установлен в nil деструктором формы, который уже убрал этот контрол из списка своих контролов... А если удалить контрол, имеющий в своём деструкторе обращение к Handle, не в момент закрытия формы, а, например, при нажатии конпки, то в этом случае исключения не произойдёт, т.к. у контрола будет до последнего и Parent, да и само уничтожение хэндла произойдёт только в унаследованном деструкторе, т.е. до вызова inherited обращение к Handle ошибок не даст...
> Krants © (11.06.07 13:27) [3] > Вообщем так работает: > procedure TControlFiles.DestroyWnd; > begin > inherited; > DragAcceptFiles(Handle,False); > end;
Бессмысленная конструкция... DestroyWnd уничтожает хэндл, поэтому обращения к Handle после inherited приводят к созданию нового окна, и в DragAcceptFiles передаётся совсем другой дескриптор...
-
> Однокамушкин
+1 Все четко и по теме. Мне понравилось. :)
-
> поэтому, если в момент обращения к Handle родитель ещё не > назначен, VCL не может создать окно и выкидывает исключение.
Чушь... Наличие родителя в данном случае синефиолетово. Проверяется наличие владельца. Если он присутствует - то происходит пострекурсивный вызов HandleNeeded.
-
Щас обсудим все внутренности VCL подетально !!! :)))
-
> > Rouse_ © (13.06.07 21:21) [7] > Чушь... Наличие родителя в данном случае синефиолетово. > Проверяется наличие владельца. Если он присутствует - то > происходит пострекурсивный вызов HandleNeeded.
Нет, не чушь... вот код из метода TWinControl.CreateWnd (Delphi 7): CreateParams(Params);
with Params do
begin
if (WndParent = 0) and (Style and WS_CHILD <> 0) then
if (Owner <> nil) and (csReading in Owner.ComponentState) and
(Owner is TWinControl) then
WndParent := TWinControl(Owner).Handle
else
raise EInvalidOperation.CreateFmt(SParentRequired, [Name]); В CreateParams поле Params.WndParent назначается в соответствии со значением свойства Parent, Owner там никак не учитывается, а в CreateWnd Owner используется только тогда, когда компонент читается из потока - видимо, в качестве временной меры, этакой заглушки при инициализации формы, пока Parent не назначен... а если, например, создавать компонент в рантайме, то эта ветка не сработвает, и как раз наличие владельца будет синефиолетово, в отличие от родителя, который проверяется всегда при флаге WS_CHILD...
-
> в качестве временной меры, этакой заглушки при инициализации > формы, пока Parent не назначен...
Ну так сдесь же речь идет о компоненте по всей видимости загружаещемся из DFM в рантайме... При чем тут остальные случаи?
-
> Rouse_ © (18.06.07 09:42) [10] > Ну так сдесь же речь идет о компоненте по всей видимости > загружаещемся из DFM в рантайме...
Интересно, как он вообще в DFM попадёт, если исключение, о котором пишет автор, возникает в момент помещения компонента на форму? Специально для проверки создал наследника TCustomControl, который обращается к Handle в своём конструкторе, так при попытке кинуть его на форму возникает эта ошибка, и на форме ничего не остаётся, так что до загрузки компонента из DFM в рантайме дело просто не доходит...
-
Хм... да. Не внимательно прочитал :)
|