![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как корректно уничтожить объект изнутри [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 кнопки пытаюсь прописать уничтожение экземпляра
> класса... глючит
а ты не пытайся .. ибо - блажь