Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Как корректно уничтожить объект изнутри [D7, WinXP]


Zilog ©   (2005-02-16 17:14:00) 

Примерно такая ситуация.
Есть экземпляр класса, в котором есть помимо прочего есть и кнопка. В OnClick кнопки пытаюсь прописать уничтожение экземпляра класса... глючит.

Выглядит всё это примерно так:

type TMyClass = class
 But : TButton;
 
end;

procedure TMyClass.OnClick(...);
begin
 Free;

end;

Непонятно, как это реализовать?


Erik1   (2005-02-18 13:31:00) [1]

А по моему вобще форточек ненадо, Applicaton.Terminate и нет проблем. Или Halt еще добавить для уверености. А вобщето для таких целей можно любой поток использовать и послать ему можно много кого.


У   (2005-02-18 13:20:00) [2]

2Digitman ©   (18.02.05 11:03) [15]
Не слишком ли расточительно получится?
Всё-таки, окно - достаточно ценный ресурс.

В принципе, для решения задачи достаточно
одного окна-почтальона:
{-----------------------------------------------------}
unit Post2Obj;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs;

procedure PostMessageToObj(Obj: TObject; Msg: Cardinal; lParam, wParam: Longint);

implementation

const
 WM_POSTMESSAGE2OBJ = WM_USER + 133;

type
 TWMPostMessage2Obj = packed record
   Msg: Cardinal;
   Dest: TObject;
   ObjMsg: PMessage;
 end;

 TPostmanWin = class(TForm)
 public
   procedure WMPostMessage2Obj(var Message: TWMPostMessage2Obj); message WM_POSTMESSAGE2OBJ;
 end;

var
 thePostman: TPostmanWin;

procedure PostMessageToObj(Obj: TObject; Msg: Cardinal; lParam, wParam: Longint);
var objMsg: PMessage;
begin
 //Обычно для синглтонов делают так:
 //if thePostman = nil then
 //  thePostman := TPostmanWin.CreateNew(nil);
 // Но в этом случае окно может создаться не в главном потоке,
 // поэтому надёжнее создать его в initialization

 New(objMsg);
 objMsg^.Msg := Msg;
 objMsg^.lParam := lParam;
 objMsg^.wParam := wParam;
 PostMessage(thePostman.Handle, WM_POSTMESSAGE2OBJ,
   Longint(Obj), Longint(objMsg));
end;

procedure TPostmanWin.WMPostMessage2Obj(var Message: TWMPostMessage2Obj);
begin
 try
   Message.Dest.Dispatch(Message.ObjMsg^);
 finally
   Dispose(Message.ObjMsg);
 end;
end;

initialization
 thePostman := TPostmanWin.CreateNew(nil);
 thePostman.Hide;

finalization
 thePostman.Free;
end.


Digitman   (2005-02-18 11:03:00) [3]


> Zilog ©   (18.02.05 10:48) [14]


а не проще ли сделать свой класс TMyClass наследником TWinControl ? чтобы не городить огород с передачей параметров-ссылок на объект ?

тогда все что тебе будет нужно - это послать сообщение StreamMsgID окну MyClass.Handle, диспетчеризацию же в общем случае автоматически выполнит цикл выборки/сообщений того потока, который создал объект твоего класса TMyClass (например, основной поток и цикл в методе Application.Run)


Zilog   (2005-02-18 10:48:00) [4]

В итоге сделал так - посылаю сообщение форме, в качестве параметров указатели - объект к которому относится сообщение, и указатель собссно на объект (из массива, который относится к предыдущему объекту) который надо удалить.

ну и удаляю:  
 TMyObj(pointer(Msg.WParam)).DeleteStream(pointer(Msg.LParam));


Alx2   (2005-02-17 16:08:00) [5]

Zilog ©   (17.02.05 15:37) [11]

Как вариант - завести киллера, который откуда-нибудь (например, из Application.OnIdle) будет вызываться и просматривать список подавших заявки на убийство.


У   (2005-02-17 15:42:00) [6]

Обработать можно, а вот послать, воспользовавшись
механизмом очереди сообщений (в чём цель) - нельзя.

Хотя в принципе можно, воспользоавшись окном-посредником.


Zilog   (2005-02-17 15:37:00) [7]

>>У   (17.02.05 15:19) [10]

спасибо, ясно.

а можно ли как то ухитриться, и в своем объекте как то обработать сообщение?


У   (2005-02-17 15:19:00) [8]

Zilog ©   (17.02.05 15:11) [9]
Сообщения, посланные с помощью PostMessage,
могут обрабатывать только объекты, являющиеся
виндовыми окнами.
К коим твой класс, как я понимаю, не относится.

Ты посылаешь сообщение форме
PostMessage(FMain.Handle,...
так и обработчик этого сообщения напиши у формы.
(в параметр его передай указатель на свой объект)


Zilog   (2005-02-17 15:11:00) [9]

>>GuAV ©   (16.02.05 18:16) [6]
>>Если наследник TForm - то Release.
>>Если контрол на форме - то слать форме WM_USER+N через >>PostMessage с контролом в качестве lParam или wParam, в >>обработчике WM_USER+N освобождать его.

Решил сделать с помощью сообщений.
Сообщение у меня должен обрабатывать объект, так же созданный динамически (невизуальный, в то время как отправители сообщений - хоть и созданы динамически, но размещаются на форме).

Сделал так:

const StreamMsgID = WM_USER + 123;

type TMyClass = class

     procedure OnStreamMessage(var Msg : TMessage); message StreamMsgId;

end;

procedure TMyIRC.OnStreamMessage(var Msg: TMessage);
begin
 Beep;
end;

procedure TMyClass.OnObjKillClick(...);
begin
 PostMessage(FMain.Handle,StreamMsgID,0,0)

end

- не работает... :(


Набережных С.   (2005-02-16 18:22:00) [10]

>Zilog ©   (16.02.05 17:45) [4]

После возврата из обработчика события код, сгенерировавший это событие, может еще многократно к этому объету. Просто поставь точку останова в своем обработчике и посмотри в окне Call Stack на каком уровне вложенности находится твой код. И большая часть предшествующих методов - методы самого объета, имеющие полное право к нему обращаться как до вызова твоего обработчика, так и после. Уничтожать объект нужно извне. Например, можно из твоего обработчика послать посредством PostMessage специальное сообщение объету, в обработчике которого и вызвать деструктор - обработчики сообщений устроены так, что это безопасно. Для формы можно использовать ее метод Release, который так и поступает.
А вообще-то я подозреваю, что ты не на том пути. Чуть раньше свернул не в ту сторону:) Вернись немного назад и еще раз подумай.


GuAV   (2005-02-16 18:17:00) [11]

Если после самоосвобождения нет попыток использовать поля класса, то можно просто free.


GuAV   (2005-02-16 18:16:00) [12]

Если наследник TForm - то Release.

Если контрол на форме - то слать форме WM_USER+N через PostMessage с контролом в качестве lParam или wParam, в обработчике WM_USER+N освобождать его.

Если фрейм - сделать что-то вроде release.


Alexander Panov   (2005-02-16 18:04:00) [13]

 TTestClass=class
 private
   FList: TStringList;
 public
   constructor Create;
   destructor Destroy;override;

   class procedure Release(aObj: TTestClass);
   class function Delete(aObj: TTestClass): Integer;

   procedure Test;
 end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 with TTestClass.Create do
 begin
   Test;
 end;
end;

{ TTestClass }

constructor TTestClass.Create;
begin
 Flist := TStringList.Create;
end;

class function TTestClass.Delete(aObj: TTestClass): Integer;
begin
 Result := 0;
 aObj.Free;
end;

destructor TTestClass.Destroy;
begin
 FList.Free;
 ShowMessage('Бобик сдох! Ёк');
 inherited;
end;

class procedure TTestClass.Release(aObj: TTestClass);
begin
 aObj.Free;
end;

procedure TTestClass.Test;
begin
 Release(Self);
end;


Zilog   (2005-02-16 17:45:00) [14]

если не сложно, не поясните ли как это сотворить?


Alexander Panov   (2005-02-16 17:25:00) [15]

используй
class procedure
или
class procedure

Передавай параметром адрес экземпляра класса.


Zilog   (2005-02-16 17:22:00) [16]

т.е. объект можно удалить, только обращением не из самого объекта?


Digitman   (2005-02-16 17:18:00) [17]


> В OnClick кнопки пытаюсь прописать уничтожение экземпляра
> класса... глючит


а ты не пытайся .. ибо - блажь


Наверх

Титульная страница Поиск, карта сайта Написать письмо