Доброго времени суток славным жителям!
Вопрос по созданию и освобождению объектов, созданных в RunTime.
Начитался я Е.Филлиповой и решил сам попробовать. Суть проста: по нажатию на кнопку "+" ниже нее создается панелька с кнопками "+" и "-", в которой по нажатию на кнопку "+" повторяется точно такая же ситуация. А вот по нажатию на кнопку "-" "родительская" панелька должна уничтожаться вместе с сендером (т.е. с кнопкой "-" и рядом лежащей кнопкой "+"). Вот тут и проблема.
interface
....
var No:Integer;
implementation
...
procedure TForm1.CreateNewPanel(Sender: TObject);
var MyPnl: array [0..4] of TPanel;
BtnPlus,BtnMinus: array [0..4] of TButton;
begin
if not(No > High(MyPnl)) then
begin
MyPnl[No]:= TPanel.Create(Form1);//создаем панель
with MyPnl[No] do//назначаем ей
begin
Height:= 30;//высоту
Name:= ClassName + IntToStr(No);//имя
Top:= Panel6.Top + Height;//верхнюю координату
Align:= alTop;//выравнивание
Parent:= Form1;//родителя
Tag:= No;
end;{with}
//создаем дочерние контролы
{TButton}
BtnPlus[No]:= TButton.Create(MyPnl[No]);
with BtnPlus[No] do
begin
{тут c OnClick разобрался}
end;
BtnMinus[No]:= TButton.Create(MyPnl[No]);
with BtnMinus[No] do
begin
BoundsRect:= Bounds(Parent.Width - 20,5,17,17);
Anchors:= Anchors + [akTop,akRight] - [akLeft,akBottom];
Name:= 'BtnMinus' + IntToStr(No);
Caption:= '-';
Parent:= MyPnl[No];
Tag:= No;
OnClick:= BtnMinusClick;
end;
Form1.Height:= Form1.Height + MyPnl[No].Height;//увеличиваем высоту формы
Form1.Refresh;//перерисовываем форму
Inc(No); //No:= No+1;//увеличиваем номер в массиве
end;{if..not(i > High(MyPnl))..then}
end;
procedure TForm1.BtnMinusClick(Sender: TObject);
begin
{пытаемся удалить панель, на которой находится сендер}
TButton(Sender).Parent.Free;//вываливается AV
end;
Насколько я понимаю, если б сендер уничтожал не самого себя а соседнюю панель, то все было бы тип-топ.
Был бы весьма признателен гуру за подсказки и возможные комментарии.
Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
20-10-2006 23:49 | Сообщение от автора вопроса
Оффтоп
>>> вы не заметили? Юрий его зовут.
Жаль, что нет возможности редактировать свои посты. Ссылку я заметил потом (картинки у меня отключены, поэтому правый край страницы "уезжает" за пределы экрана, приходится скролить вправо). А ввобще, приятно, что модератор форума так чутко реагирует на общение - значит, все тут в порядке с порядком (каламбур). Буду заглядывать сюда в первую очередь ))
огромнейший респект, особенно Ins (жаль, не знаю имени) за терпение и конструктивизм. Все получилось просто и изящно. Поскольку этого ребуют правила, привожу код того, что у меня получилось (и заработало).
{добавлено в раздел interface - остальной код в первом посте}
interface
procedure TForm1.MyBtnMinusClick(Sender: TObject);
begin
No:= TButton(Sender).Tag - 1;
if No > Low(MyBtnMinus)//если сендер - кнопка не из первой панели (MyPnl[0])
then
begin//фокус на собратьев любой из массива панелей MyPnl
MyBtnPlus[No-1].Enabled:= True;
MyBtnMinus[No-1].Enabled:= True;
MyBtnMinus[No-1].SetFocus;
end
else//иначе выше лежит "постоянная" панель, созданный в OnCreate формы
begin
BtnPlus.Enabled:= True;
BtnPlus.SetFocus;//фокус на "постоянную" кнопку
end;
Form1.Height:= Form1.Height - MyPnl[No].Height;//уменьшаем высоту формы
Form1.Refresh;//перерисовываем форму
Почему так происходит, что из обработчика OnClick нельзя уничтожить объект, вызвавший это событие?
Что происходит, когда пользователь отпускает левую кнопку мыши над кнопкой:
1. Вызывается метод WMLButtonUp класса TControl.
procedure TControl.WMLButtonUp(var Message: TWMLButtonUp);
begin
inherited;
if csCaptureMouse in ControlStyle then MouseCapture := False;
if csClicked in ControlState then
begin
Exclude(FControlState, csClicked);
if PtInRect(ClientRect, SmallPointToPoint(Message.Pos)) then Click;
end;
DoMouseUp(Message, mbLeft);
end;
2. Как видно, из этого метода вызывается метод Click.
procedure TControl.Click;
begin
{ Call OnClick if assigned and not equal to associated action's OnExecute.
If associated action's OnExecute assigned then call it, otherwise, call
OnClick. }
if Assigned(FOnClick) and (Action <> nil) and (@FOnClick <> @Action.OnExecute) then
FOnClick(Self)
else if not (csDesigning in ComponentState) and (ActionLink <> nil) then
ActionLink.Execute(Self)
else if Assigned(FOnClick) then
FOnClick(Self);
end;
3. То есть из этого метода происходит вызов определенного вами обработчика события OnClick.
4. В методе OnClick вы уничтожаете экземпляр класса.
5. После возврата из обработчика события, управление возвращается в метод Click, а так как там больше никаких действий производить не нужно - тут же в метод WMLButtonUp.
6. Далее должна выполниться строчка
DoMouseUp(Message, mbLeft);
или другими словами
self.DoMouseUp(Message, mbLeft);
Но ведь экземпляр self уже уничтожен!
Приведенный ниже способ заставляет объект уничтожиться после того, как будет полностью обработано сообщение мыши.
Вот один из способов самоубийства объектов (по аналогии с методом форм Release). Кидаем на форму панель, на нее - кнопку. По нажатии на кнопку, панель с кнопкой уничтожиться.
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.