![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Непонимаю почему не работает [D7]
boleg © (2006-12-29 10:40:00)Страннно компилятор пропускает, а на епапе выполнения выдается ошибка типа "Access violation at address". Если уважаемому ALL эти потуги новичка не покажутся скучными :-) то объясните почему не работает:
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure PanelDblClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
Panel: TPanel;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
Panel:=TPanel.Create(Self);
Panel.Top:=100;
Panel.Left:=100;
Panel.Parent:=Self;
Panel.OnDblClick:=PanelDblClick;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
Panel.Free;
end;
procedure TForm1.PanelDblClick(Sender: TObject);
begin
// TPanel(Sender).Caption:='rrrrrrrrrr';
TPanel(Sender).Free; // выдает ошибку, хотя верхняя рабртает
end;
end.
boleg (2006-12-29 17:56:00) [1]Спасибо, думаю что разобрался
Gloomer (2006-12-29 13:00:00) [2]IMHO прав [19]
procedure TForm1.Button1Click(Sender: TObject);
var Panel: TPanel;
begin
Panel:=TPanel.Create(Self);
Panel.Top:=100;
Panel.Left:=100;
Panel.Parent:=Self;
Panel.OnDblClick:=PanelDblClick;
Panel.OnMouseDown:=PanelMouseDown;
end;
procedure TForm1.PanelDblClick(Sender: TObject);
begin
TPanel(Sender).Tag:=666;
end;
procedure TForm1.PanelMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
with TPanel(Sender) do
if Tag=666 then Free;
end;
C (2006-12-29 12:59:00) [3]>Джо © (29.12.06 12:46) [25]
Не понял, честно говоря, как это связано:( Тем более, что нигде в приведенном в [20] коде nil не присваивается и, соответственно, Self не будет равен nil даже после уничтожения объекта.
Возможно, я выразился недостаточно ясно. Имелось в виду, что в общем случае метод, отправляющий WM_KILL может быть вызван 2 или более раз до того как первое из них будет выбрано из очереди и обработано. Соответственно в очереди окажутся несколько сообщений WM_KILL для одного и того же объекта. И тогда при обработке первого из них объект будет уничтожен, а при обработке второго в Msg.WParam окажется указатель на уже уничтоженный объект. И Self во Free тоже будет равен значению Msg.WParam <> nil.
Джо (2006-12-29 12:46:00) [4]> [24] C (29.12.06 12:25)
> >Джо © (29.12.06 12:17) [23]
>
> На случай, если он успеет отправить несколько сообщений
> до того, как будет выбрано и обработано первое сообщение-
> киллер. "Маловероятно" не значит "невозможно". Разве нет?
В методе Free проверяется не равен ли Self nil и только после этого идет вызов Destroy.
C (2006-12-29 12:25:00) [5]>Джо © (29.12.06 12:17) [23]
На случай, если он успеет отправить несколько сообщений до того, как будет выбрано и обработано первое сообщение-киллер. "Маловероятно" не значит "невозможно". Разве нет?
Джо (2006-12-29 12:17:00) [6]> [22] С (29.12.06 12:07)
> >Джо © (29.12.06 11:50) [20]
>
> Желательно все-же добавить эащиту от попатки многократного
> удаления одной и той же панели.
Это зачем?
С (2006-12-29 12:07:00) [7]>Джо © (29.12.06 11:50) [20]
Желательно все-же добавить эащиту от попатки многократного удаления одной и той же панели. Например, кроме отравки сообщения еще и удалять обработчик события. Ну или свойство Tag использовать в качестве флага.
Elen (2006-12-29 11:54:00) [8]Удалено модератором
Примечание: Флудить завязываем
Джо (2006-12-29 11:50:00) [9]> [18] Elen © (29.12.06 11:40)
>
> > Как всетаки сделать чтобы работало.
>
> Если тебе надо удалять объект по которому ты клацнул то
> можно попробовать так :
Это называется удалять гланды через кое-что :)
Стандартно поступают так:
const
WM_KILL = WM_USER + 666;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
procedure WmKillMem (var Msg: TMessage); message WM_KILL;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
PostMessage (Handle,WM_KILL,Integer(Sender),0)
end;
procedure TForm1.WmKillMem(var Msg: TMessage);
begin
TObject(Msg.WParam).Free
end;
C (2006-12-29 11:49:00) [10]>boleg © (29.12.06 11:33) [15]
А какой тут можно пример? Надо смотреть исходный код TPanel и его предков, то есть всю трассу вызовов от цикла выборки сообщений до вызова обработчика OnDoubleClick и обратно, до цикла выборки. В частности, после вызова обработчика двойного клика происходит проверка наличия и вызов события OnMouseDown - то есть попытка обратиться к полю FOnMouseDown уже уничтоженного объекта. Причем ошибка может проявляться нестабильно, то появляться, то пропадать, так что лучше взять за аксиому [7].
Elen (2006-12-29 11:40:00) [11]
> Как всетаки сделать чтобы работало.
Если тебе надо удалять объект по которому ты клацнул то можно попробовать так :
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, extctrls;
type
TForm1 = class(TForm)
Button1: TButton;
Timer1: TTimer;
procedure Button1Click(Sender: TObject);
procedure PanelDblClick(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var pn,Panel: TPanel;
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.PanelDblClick(Sender: TObject);
begin
Caption:=TPanel(Sender).Name;
pn:=TPanel(Sender);
Timer1.Enabled:=true;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Panel:=TPanel.Create(Self);
Panel.Name:='n'+inttostr(random(100));
Panel.Top:=random(100);
Panel.Left:=100;
Panel.Parent:=Self;
Panel.OnDblClick:=PanelDblClick;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
pn.Free; Timer1.Enabled:=false;
end;
end.
umbra (2006-12-29 11:38:00) [12]
> Как всетаки сделать чтобы работало
чтобы работало что? чего надо добиться?
Elen (2006-12-29 11:36:00) [13]
> boleg
Sorry но [13] работает только для одной создаваемой панели. (см. [7])
пробуй так :
....................
var pn,Panel: TPanel;
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.PanelDblClick(Sender: TObject);
begin
Caption:=TPanel(Sender).Name;
pn:=TPanel(Sender);
end;
..................
procedure TForm1.Button2Click(Sender: TObject);
begin
pn.Free;
end;
boleg (2006-12-29 11:33:00) [14]"После возврата из обработчика метод TPanel, который этот обработчик вызывает, пытается обратиться к полям объекта, для которого и произошло событие, а объект оказывается уже уничтоженным, отсюда и ошибка".
Прошу пояснить, если не трудно, примером. Как всетаки сделать чтобы работало.
P.S. Прошу прощения за настырность. Но хочу разобраться дабы не задавать глупых вопросов!
Desdechado (2006-12-29 11:31:00) [15]внимательно читай umbra © (29.12.06 11:11) [7]
Elen (2006-12-29 11:29:00) [16]
> немного изменив получилалось так как приведено
Немного изменив привожу свое, може поможет. (у меня робэ) :
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, extctrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure PanelDblClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var Panel: TPanel;
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.PanelDblClick(Sender: TObject);
begin
TPanel(Sender).Caption:='rrrrrrrrrr';
TPanel(Sender).Free; // âûäàåò îøèáêó, õîòÿ âåðõíÿÿ ðàáðòàåò
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Panel:=TPanel.Create(Self);
Panel.Top:=100;
Panel.Left:=100;
Panel.Parent:=Self;
Panel.OnDblClick:=PanelDblClick;
end;
end.
Хотя [7] конечно верно...
Elen (2006-12-29 11:28:00) [17]
> Так вот
...
> работает !!
>
> а так
...
> работает. Почему не могу понять.
Улыбнуло.
У меня твое работает при некоторой доработке
А где у тебя описание Button2Click
boleg (2006-12-29 11:25:00) [18]Для Umbra
Такой пример вычитал в книге М.Фленов "Библия Delphi", немного изменив получилалось так как приведено. :-)
С (2006-12-29 11:24:00) [19]"Она живет на улице койкого, а он на улице койкого"©
boleg (2006-12-29 11:18:00) [20]Прошу прощения procedure TForm1.Button2Click(Sender: TObject) забыл стереть
дабы не отвлекать внимание. Эта процедура работает. Но работает не так как нужно. Например, если нажать несколько раз на Button1 (создавая несколько панелек на форме), то при нажатии на Button2 первый екземпляр удаляется, а вот повторное нажатие вызывает ошибку (теряет ссылку на объект). Поэтому была придумана
procedure TForm1.PanelDblClick(Sender: TObject)
По двойному клику удалять панели с формы, ссылаясь на них TPanel(Sender)
где Sender - указатель на панельку.
Так вот
procedure TForm1.PanelDblClick(Sender: TObject);
begin
TPanel(Sender).Caption:='rrrrrrrrrr';
end;
работает !!
а так
procedure TForm1.PanelDblClick(Sender: TObject);
begin
TPanel(Sender).Free;
end;
работает. Почему не могу понять.