Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > [ "Начинающим" ]
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 17.08.2009, 00:16
Аватар для Oleg
Oleg Oleg вне форума
Активный
 
Регистрация: 29.11.2007
Адрес: Оренбургская обл., Россия
Сообщения: 261
Репутация: 15
Вопрос Удаление переменных

Здравствуйте, у меня вопрос, с которым вот уже несколько дней не могу разобраться.
Переделал всё на максимально простой уровень, чтобы всем было понятно.
Допустим у нас есть процедура:
----------
Случай 1
----------
Код:
Procedure AddObject;
var
myObject:TButton;
begin
myObject:=TButton.Create(Form1);
myObject.Caption:='Test Button';
myObject.Parent:=Form1;
AddToList(myObject);
// и т.п.
end;
Этот объект используется до какого-то момента, но как его затем удалить не из этой процедуры ?
может нужно как-то создать массив, в котором будут указатели(но у меня не получается) .
----------
Случай 2
----------
Если этот объект объявлен в глобальных переменных:
Код:
var
  myObject:TButton;
  Ptr:^TButton;
и я его создаю в этой процедуре, то я могу его удалить, модернизировав эту процедуру так:
Код:
 Procedure AddToList(var Obj:TButton);
 begin
 Ptr:=Addr(Obj);
 end;


Procedure AddObject;
begin
myObject:=TButton.Create(Form1);
myObject.Caption:='Test Button';
myObject.Parent:=Form1;
AddToList(myObject);
// и т.п.
end;


Procedure DeleteObj;
begin
FreeAndNil(Ptr^);
end;
Так всё прекрасно работает, но только в том случае, если объект этот глобальный, а если он локальный, то как тогда быть ???
______________________
немного другой вопрос:
----------
Случай 3
----------
допустим у нас это переменная глобальная:
Код:
var
myObject:TButton;
а я с помощью той процедуры добавления создаю несколько один их тех же объектов, но уже создал предварительно массив указателей:
Код:
var // глобальные переменные
  myObject:TButton; 
  Ptr:array[1..100] of ^TButton; 
  Count:Integer;
теперь наш код выглядит вот так:
Код:
 Procedure AddToList(var Obj:TButton);
 begin
 Inc(Count);
 Ptr[Count]:=Addr(Obj);
 end;

Procedure AddObject;
begin
myObject:=TButton.Create(Form1);
myObject.Caption:='Test Button'+IntToStr(Random(1000));
myObject.Parent:=Form1;
myObject.Left:=Random(100);
MyObject.Top:=Random(50);
AddToList(myObject);
// и т.п.
end;


Procedure DeleteObj;
var
i:integer;
begin
For i:=1 to Count do
FreeAndNil(Ptr[i]^);
end;
Помогите пожалуйста разобраться как реализовать нормальное удаление, а то если использовать последний случай, то удаляется лишь один объект(добавленный последним) и всё
__________________
Если Вы находите ошибки, исправить которые дело долгое и нудное, ничего не делайте - просто внесите их в список особенностей

Последний раз редактировалось Oleg, 17.08.2009 в 20:34. Причина: возник вопрос, который не дает покоя :(
Ответить с цитированием
  #2  
Старый 17.08.2009, 22:10
Аватар для Oleg
Oleg Oleg вне форума
Активный
 
Регистрация: 29.11.2007
Адрес: Оренбургская обл., Россия
Сообщения: 261
Репутация: 15
По умолчанию Продвижение...

Сделал вот так:
Код:
var
  Ptr:array[1..100] of ^TButton;
  Count:Integer;

//==========================


 Procedure AddToList(var Obj:TButton);
 begin
 Inc(Count);
 Ptr[Count]:=Addr(Obj);
 end;


Procedure AddObject;
var
  myObject:^TButton;
begin
new(myObject);
myObject^:=TButton.Create(Form1);
myObject^.Caption:='Test Button'+IntToStr(Random(1000));
myObject^.Parent:=Form1;
myObject^.Left:=Random(100);
MyObject^.Top:=Random(50);
AddToList(myObject^);
// и т.п.
end;


Procedure DeleteObj;
var
i:integer;
begin
For i:=1 to Count do
FreeAndNil(Ptr[i]^);
end;

Код:
Procedure DeleteObj;
var
i:integer;
begin
For i:=1 to Count do
 IF Assigned(Ptr[i]) and Assigned(Ptr[i]^) then
 begin
 FreeAndNil(Ptr[i]^);
 Dispose(Ptr[i]);
 Ptr[i]:=nil;
end;
end;
Вот так всё работает, ура))))))
__________________
Если Вы находите ошибки, исправить которые дело долгое и нудное, ничего не делайте - просто внесите их в список особенностей

Последний раз редактировалось Oleg, 17.08.2009 в 22:38.
Ответить с цитированием
  #3  
Старый 18.08.2009, 06:30
Аватар для 0nni
0nni 0nni вне форума
Начинающий
 
Регистрация: 13.12.2008
Адрес: Туапсе
Сообщения: 161
Репутация: 20
По умолчанию

У всез компонентов есть своейство Components b и ComponentsCount;
Создай например глобальный объект ButtonOwner : TComponent; (не забудь создать в процедуре onCreate)

Код:
Procedure AddObject;
var
myObject:TButton;
begin
myObject:=TButton.Create(ButtonOwner);
myObject.Caption:='Test Button';
myObject.Parent:=Form1;
// и т.п.
end;
удаеление последней конпки будет выглядеть так
Код:
  if ButtonOwner.ComponentsCount <> 0 then
  ButtonOwner.Components[ButtonOwner.ComponentsCount - 1].Free;
Для удаления всех кнопок есть мтоде FreeAllComponents (если не путаю).

Но лучший вариант - воспользоваться списками TList или TObjList
__________________
...сказал, и загрустил от бесспорной своей правоты
Ответить с цитированием
  #4  
Старый 18.08.2009, 14:38
Аватар для Oleg
Oleg Oleg вне форума
Активный
 
Регистрация: 29.11.2007
Адрес: Оренбургская обл., Россия
Сообщения: 261
Репутация: 15
Стрелка

>> 0nni
так не пойдет, я кнопку взял лишь для примера, у меня свои классы другие.
__________________
Если Вы находите ошибки, исправить которые дело долгое и нудное, ничего не делайте - просто внесите их в список особенностей
Ответить с цитированием
  #5  
Старый 18.08.2009, 15:17
Аватар для 0nni
0nni 0nni вне форума
Начинающий
 
Регистрация: 13.12.2008
Адрес: Туапсе
Сообщения: 161
Репутация: 20
По умолчанию

Замени класс TButton на любой другой класс, в чем проблема?
__________________
...сказал, и загрустил от бесспорной своей правоты
Ответить с цитированием
  #6  
Старый 18.08.2009, 15:30
Аватар для 0nni
0nni 0nni вне форума
Начинающий
 
Регистрация: 13.12.2008
Адрес: Туапсе
Сообщения: 161
Репутация: 20
По умолчанию

Сделай вот такие изменения и все будет работать с локальным объектом.
Код:
Ptr:array[1..100] of TButton;
Ptr:TButton;
Код:
 Procedure AddToList(Obj:TButton);
 begin
 Ptr:=Obj
 end;

Код:
Procedure DeleteObj;
var
i:integer;
begin
For i:=1 to Count do
FreeAndNil(Ptr[i]);
end;

Вообще не мешало бы тебе почитать что есть указатель, что есть локальная переменная и почему указатель на него не рекомендутеся передавать, и что такое объект и почему указатель PObject = ^TObject - это глупо.
__________________
...сказал, и загрустил от бесспорной своей правоты
Ответить с цитированием
  #7  
Старый 18.08.2009, 17:12
Аватар для Oleg
Oleg Oleg вне форума
Активный
 
Регистрация: 29.11.2007
Адрес: Оренбургская обл., Россия
Сообщения: 261
Репутация: 15
Печаль

Массив мне не подойдет, если бы он мне подходил, то я бы не задавал подобный вопрос.

>>"Вообще не мешало бы тебе почитать что есть указатель, что есть локальная переменная" всё это читал.
>> "и почему указатель на него не рекомендутеся передавать" почему ?
>> "и что такое объект и почему указатель PObject = ^TObject - это глупо." почему ?
__________________
Если Вы находите ошибки, исправить которые дело долгое и нудное, ничего не делайте - просто внесите их в список особенностей

Последний раз редактировалось Oleg, 18.08.2009 в 17:19.
Ответить с цитированием
  #8  
Старый 18.08.2009, 18:14
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,035
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Есть класс TObjectList.
У него есть свойство - OwnObjects. Тогда достаточно просто удалить объект из этого класса и объект будет удален.

Кнопка - для примера.
Код:
type
  TForm1 = class(TForm)
  ...
  private
     FList : TObjectList;
  ...
  end;

...

procedure TForm1.FromCreate(Sender : TObject);
begin
  FList := TObjectList.Create(True);
end;

procedure TForm1.FromDestroy(Sender : TObject);
begin
  FList.Free;
end;

procedure TForm1.CreateButton(ACaption : String);
var
  AButton : TButton;
begin
  AButton := TButton.Create(Nil); // !! Важно !! Если классы свои - то пофиг.
  AButton.Caption := ACaption;
  FList.Add(AButton);

  AButton.Parent := Self; // Это для визуальных контролов. Надо же ее показать :)
end;

// Удаляем по заголовку, просто пример.
procedure TForm1.DeleteButton(ACaption : String);
var
  I  : Integer;
begin
  For I := FList.Count-1 DownTo 0 Do
    If (Flist[i] As TButton).Caption = ACaption Then FList.Delete[i];
end;
Ответить с цитированием
  #9  
Старый 18.08.2009, 18:51
Аватар для 0nni
0nni 0nni вне форума
Начинающий
 
Регистрация: 13.12.2008
Адрес: Туапсе
Сообщения: 161
Репутация: 20
По умолчанию

Цитата:
Сообщение от Oleg
почему ?
Код:
program Project3;

{$APPTYPE CONSOLE}

uses
  Windows;

function GetPointerA : PInteger;
var
  a : integer;
begin
  a := 10;
  result := @a;
end;

var
  PointerA : PInteger;

begin
  PointerA := GetPointerA;
  MessageBeep(0);
  Writeln(PointerA^);
  ReadLn;
end.
Попробуй угадать что за число окажется в консоли. А теперь откомпилируй и убедись что не угадал. А теперь убери MessageBeep(0) - черная магия?

По поводу объектов - объект это и есть указатель.
Код:
procedure SetButtonCaption(btn : TButton);
begin
  btn.Caption := 'Hello world!';
begin;
__________________
...сказал, и загрустил от бесспорной своей правоты
Ответить с цитированием
  #10  
Старый 18.08.2009, 18:57
Аватар для Oleg
Oleg Oleg вне форума
Активный
 
Регистрация: 29.11.2007
Адрес: Оренбургская обл., Россия
Сообщения: 261
Репутация: 15
Вопрос Спасибо

lmikle, спасибо конечно, но либо название класса неправильное(TObjectList), либо я не знаю в каком он модуле находится.
Этот класс тоже конечно полезный, но объясню как мне нужно в данный момент.
Допустим у меня есть класс:
Код:
  TestClass = class
  public
  Ptr:^TButton;
  Constructor Create(var Obj:TButton);
  end;

Constructor TestClass.Create(var Obj:TButton);
begin
Inherited Create;
Ptr:=@Obj;
end;
____________
кажется, если это глобальная переменная, то всё работает...
А как быть, если это локальная ?
__________________
Если Вы находите ошибки, исправить которые дело долгое и нудное, ничего не делайте - просто внесите их в список особенностей

Последний раз редактировалось Oleg, 18.08.2009 в 19:19.
Ответить с цитированием
  #11  
Старый 18.08.2009, 20:51
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,035
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Он в модуле Contnrs

Точно так же.
Дело в том, что объект - уже указатель. Так что Ptr := @Obj должно быть Ptr := Obj. А память, выделяемая конструктором, никак не связана с тем, локльная это переменная или глобальная. Она просто выделена. Если создан объект в локальной переменной, и она выходит за область видимости, то ты получаешь утечку памяти, т.к. выделенная память не освобождается.
Тут скорее вопрос, зечем тебе такая обертка? Я не иже в ней смысла.
Ответить с цитированием
  #12  
Старый 18.08.2009, 21:47
Аватар для Oleg
Oleg Oleg вне форума
Активный
 
Регистрация: 29.11.2007
Адрес: Оренбургская обл., Россия
Сообщения: 261
Репутация: 15
Сообщение

Проблема в том, что я программирую и пишу классы под 3D графику, есть свои классы объектов и т.п.
так вот, чтобы контролировать уничтожение объектов, я ввел такое свойство как Destroyng, как только это свойство истинно, то объект уничтожает другая класс, который контролирует все эти объекты, НО этот объект может использоваться и другими процедурами, классами и т.п., если не проверять существует ли этот объект или нет, то вылетает ошибка, т.к. что-то или кто-то пытается получить какие-то данные с объекта, которого уже нет . хоть и стоят проверки Assigned, всё равно такое неприятное явление наблюдается, пытаюсь вот придумать как сделать всё правильно, поэтому хотел использовать указатель на реальный объект и проверять именно через него.
__________________
Если Вы находите ошибки, исправить которые дело долгое и нудное, ничего не делайте - просто внесите их в список особенностей
Ответить с цитированием
  #13  
Старый 19.08.2009, 00:10
Аватар для 0nni
0nni 0nni вне форума
Начинающий
 
Регистрация: 13.12.2008
Адрес: Туапсе
Сообщения: 161
Репутация: 20
По умолчанию

Код:
unit Unit1;

interface

type
  //базоый объект
  TMyCustomObject = class
    constructor Create;
    destructor Destroy; override;
  end;

procedure Clear;
function IsValidObject(Obj : TObject) : Boolean;

implementation

Uses
  Classes;

var
  Objects : TList;

procedure Clear;
var
  i : Integer;
begin
  for I := 0 to Objects.Count - 1 do TObject(Objects[0]).free;
end;

//функция проверки
function IsValidObject(Obj : TObject) : Boolean;
begin
  Result := Objects.IndexOf(Obj) <> -1;
end;

{ TMyCustomObject }

constructor TMyCustomObject.Create;
begin
  Objects.Add(self);
end;

destructor TMyCustomObject.Destroy;
var
  index : Integer;
begin
  index := Objects.IndexOf(self);
  if index <> -1 then Objects.Delete(index);
  inherited;
end;

initialization

  Objects := TList.Create;

finalization
  Clear;
  Objects.Free;
end.
__________________
...сказал, и загрустил от бесспорной своей правоты
Ответить с цитированием
  #14  
Старый 19.08.2009, 01:57
Аватар для Oleg
Oleg Oleg вне форума
Активный
 
Регистрация: 29.11.2007
Адрес: Оренбургская обл., Россия
Сообщения: 261
Репутация: 15
По умолчанию

Спасибо, 0nni, я уже пробовал через TList, но буду всё же использовать массивы, т.к. именно для данной задачи это будет более простым способом и надежным.
Спасибо за активность.
__________________
Если Вы находите ошибки, исправить которые дело долгое и нудное, ничего не делайте - просто внесите их в список особенностей
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 03:13.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2023

ВКонтакте   Facebook   Twitter