Модераторы: Snowy, MetalFan, bems, Poseidon
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Работа с TObjectList, Что-то я запутался совсем 
:(
    Опции темы
AlexLogos
Дата 17.3.2010, 19:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 229
Регистрация: 23.4.2009

Репутация: нет
Всего: 1



Решил немного переделать прогу и использовать вместо масива обьектов клас TObjectList, но так как никогда с ним не работал то возникли вопросы...
Народ, подскажите, создаю я некий клас:
Код

type CTableField = class
     Lab:TLabel;
     Ed:TControl;
     field_name:string[20];
     description:string[50];
     field_type:string[20];
     field_class:string[20];
end;

var
 CTableFields:TObjectList;
 TableField:CTableField;



создаю и отображаю на форме елементы согласно файлу конфигурации:
Код

procedure TableInputForm(InputParent:TWinControl; Section:string);
var
sections:TStringList;
st:string;
res:widestring;
i,p:cardinal;
begin
 try
  with IniFile do
   begin
    if SectionExists(Section+'_OUT') then
     begin
      try
       CTableFields:=TObjectList.Create(True);
       sections:=TStringList.Create;
       ReadSectionValues(Section+'_OUT',sections);
       SetLength(TableFields,sections.Count);
       InputParent.Height:=25*sections.Count+80;
       for i:=0 to sections.Count-1 do
        begin
         st:=sections.Strings[i];
         p:=pos('=',st);
         TableField:=CTableField.Create;
         TableField.field_name:=copy(st,1,p-1);
         TableField.Ed:=TEdit.Create(InputParent);
         with TEdit(TableField.Ed) do
          begin
           Name:=TableFields[i].field_name;
           Width:=100;
           Height:=20;
           Text:=IntToStr(i);
           Left:=230;
           Top:=25*(i+2);
           Parent:=InputParent;
           Visible:=true;
          end;

         delete(st,1,p);
         p:=pos('^',st);
         TableField.description:=copy(st,1,p-1);
         TableField.Lab:=TLabel.Create(InputParent);
         TableField.Lab.Name:='Lab_'+TableField.field_name;
         TableField.Lab.Width:=200;
         TableField.Lab.Height:=20;
         TableField.Lab.Caption:=TableField.description;
         TableField.Lab.Left:=30;
         TableField.Lab.Top:=25*(i+2);
         TableField.Lab.Parent:=InputParent;
         TableField.Lab.Visible:=true;
         delete(st,1,p);
         p:=pos('^',st);
         if p>0 then
          begin
           TableField.field_type:=copy(st,1,p-1);
           TableField.field_class:=copy(st,p+1,Length(st)-(p));
          end
         else TableField.field_type:=copy(st,1,Length(st));
         CTableFields.Add(TableField);
        end;
      finally
       sections.Free;
      end;
     end;
   end;
 finally
  IniFile.Free;
 end;
end;


Вопрос: как правильно очистить CTableFields:TObjectList и соответственно форму? Пробую и так и этак - ну никак...
PM MAIL   Вверх
RomanEEP
Дата 17.3.2010, 21:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 424
Регистрация: 18.5.2006
Где: Коломна

Репутация: 1
Всего: 8



Код

type CTableField = class
     Lab:TLabel;
     Ed:TControl;
     field_name:string[20];
     description:string[50];
     field_type:string[20];
     field_class:string[20];
  destructor Destroy; override;  
end;

destructor CTableField.Destroy; 
begin
  Lab.Free;
  Ed.Free;
  inherited;
end;

Теперь всё очищается одной строчкой
CTableFields.Free;
или, что лучше
FreeAndNil(CTableFields);

PM MAIL   Вверх
AlexLogos
Дата 18.3.2010, 10:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 229
Регистрация: 23.4.2009

Репутация: нет
Всего: 1



Бывалый, очень благодарен за помощь. Конечно все зараюотало как надо!
PM MAIL   Вверх
AlexLogos
Дата 19.3.2010, 19:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 229
Регистрация: 23.4.2009

Репутация: нет
Всего: 1



Не могу себе позволить не обратиться к вам еще раз потому что сам не вытягиваю - знаний мало. Значит намудрил я здоровенный клас и его конструкторы-деструктори:
Код

type CTableField = class     //Клас, який описує поле для вводу
     Lab:TLabel;
     Ed:TControl;
     field_name:string[20];
     description:string[50];
     field_type:string[20];
     field_class:string[20];
     destructor Destroy; override;
end;

type CTableFieldCollecton = class(TObjectList)
     public
     constructor Create(InputParent:TWinControl; Section:string);
     destructor Destroy; override;
end;

type FMainTableForm = class //клас який описує форму головної таблиці
     MainTableFormName:TComponentName;
     MainPanel:TPanel;
     TopPanel:TPanel;
     CloseExpandButton:TSpeedButton;
     MainScroll:TScrollBox;
     ScrollPanel:TPanel;
     BottomPanel:TPanel;
     SaveButton:TButton;
     FieldCollection:CTableFieldCollecton;
     public
     constructor Create(AOwner:TWinControl;Section:string; Main:boolean);
     destructor Destroy; override;
     procedure SaveButtonClick(Sender:TObject);
     procedure CloseExpandButtonButtonClick(Sender:TObject);
end;

var
 IniFile:TIniFile;     // Всім відомий іні-файл
 CTableFields:TObjectList; // Список полів для форми які беруться з іні-файлу
 //TableFieldCollection:CTableFieldCollecton;
 TableField:CTableField; //Поле яке створюється і додається в список полів
 MainTableForm:FMainTableForm;  //Форма для головної таблиці
 //SubTableForm:FSubTableForm;  //Форма для додаткович, звязаних таблиць
implementation

destructor CTableFieldCollecton.Destroy;
var i:cardinal;
begin
 for i := 0 to Count - 1 do
  Items[i].Destroy;
 inherited;
end;

destructor CTableField.Destroy;
begin
  if Lab<>nil then Lab.Free;
  if Ed<>nil then Ed.Free;
  inherited;
end;

destructor FMainTableForm.Destroy;
begin
  FreeAndNil(FieldCollection);
  if CloseExpandButton<>nil then CloseExpandButton.Free;
  if TopPanel<>nil then TopPanel.Free;
  SaveButton.Free;
  ScrollPanel.Free;
  BottomPanel.Free;
  MainScroll.Free;
  MainPanel.Free;
  inherited;
end;

procedure FMainTableForm.SaveButtonClick(Sender:TObject);
begin
 MainTableForm.Destroy;
end;

constructor FMainTableForm.Create(AOwner:TWinControl; Section:string; Main:boolean);
begin

MainTableFormName:=Section;
MainPanel:=TPanel.Create(AOwner);
MainPanel.Parent:=AOwner;
MainPanel.Align:=alClient;
MainPanel.Visible:=True;
if not(Main) then
 begin
  TopPanel:=TPanel.Create(MainPanel);
  TopPanel.Parent:=MainPanel;
  TopPanel.Align:=alTop;
  TopPanel.Height:=15;
  TopPanel.Visible:=True;

  CloseExpandButton:=TSpeedButton.Create(TopPanel);
  CloseExpandButton.Parent:=TopPanel;
  CloseExpandButton.Height:=15;
  CloseExpandButton.Width:=60;
  CloseExpandButton.Anchors:=[akLeft,akTop];
  CloseExpandButton.Top:=0;
  CloseExpandButton.Left:=20;
  CloseExpandButton.OnClick:=CloseExpandButtonButtonClick;
 end;

MainScroll:=TScrollBox.Create(MainPanel);
MainScroll.Parent:=MainPanel;
MainScroll.Align:=alClient;
MainScroll.Visible:=True;

ScrollPanel:=TPanel.Create(MainScroll);
ScrollPanel.Parent:=MainScroll;
ScrollPanel.Align:=alTop;
ScrollPanel.Height:=400;
ScrollPanel.Visible:=True;

FieldCollection:=CTableFieldCollecton.Create(ScrollPanel,Section);

BottomPanel:=TPanel.Create(MainPanel);
BottomPanel.Parent:=MainPanel;
BottomPanel.Align:=alBottom;
BottomPanel.Height:=40;
BottomPanel.Visible:=True;

SaveButton:=TButton.Create(BottomPanel);
SaveButton.Parent:=BottomPanel;
SaveButton.Width:=100;
SaveButton.Height:=20;
SaveButton.Anchors:=[akRight,akTop];
SaveButton.Top:=10;
SaveButton.Left:=400;
SaveButton.Caption:='"Save"';
SaveButton.Visible:=True;
SaveButton.OnClick:=SaveButtonClick;
end;

constructor CTableFieldCollecton.Create(InputParent:TWinControl; Section:string);
var
sections:TStringList;
st:string;
res:widestring;
i,p,duz1,duz2,field_size,top_value,top_offset:cardinal;
visible_field:boolean;
begin
 try
  IniFile:=TIniFile.Create(ExtractFilePath(paramstr(0))+'ini\setup.ini');
  with IniFile do
   begin
    if SectionExists(Section+'_ALL') then
     begin
      try
       sections:=TStringList.Create;
       ReadSectionValues(Section+'_ALL',sections);
       res:='';
       top_value:=50;
       for i:=0 to sections.Count-1 do
        begin
         st:=sections.Strings[i];

         visible_field:=true;
         p:=pos('*',st);
         if p>0 then
          begin
            visible_field:=false;
            System.Delete(st,p,1);
          end;

         p:=pos('=',st);
         TableField:=CTableField.Create;
         TableField.field_name:=copy(st,1,p-1);
         System.delete(st,1,p);
         p:=pos('^',st);
         TableField.description:=copy(st,1,p-1);
         System.delete(st,1,p);
         p:=pos('^',st);
         if p>0 then
          begin
           TableField.field_type:=copy(st,1,p-1);
           TableField.field_class:=copy(st,p+1,Length(st)-(p));
          end
         else TableField.field_type:=copy(st,1,Length(st));//TableFields[i].field_type:=copy(st,1,Length(st));
        // res:=res+'"'+ TableField.field_name+'"'+TableField.description+'"'+TableField.field_type+'"'+TableField.field_class+'"'+chr(13)+chr(10);
         if pos('VARCHAR2',TableField.field_type)>0 then
          begin
           duz1:=pos('(',TableField.field_type);
           duz2:=pos(')',TableField.field_type);
           if (duz1>0)and(duz2>0)and(duz2>duz1) then
            begin
             field_size:=StrToInt(copy(TableField.field_type,duz1+1,duz2-duz1-1));
            end
           else field_size:=15;
           if field_size<=40 then
            begin
             TableField.Ed:=TEdit.Create(InputParent);
             with TEdit(TableField.Ed) do
              begin
               if visible_field then top_offset:=25;
               //top_value:=top_value+25;
               Width:=field_size*9;
               Height:=20;
               Text:=IntToStr(field_size);
              end;
             end
           else
            begin
             TableField.Ed:=TMemo.Create(InputParent);
             with TMemo(TableField.Ed) do
              begin
//Задаю свойства
               if visible_field then top_offset:=Height+5;

              end;
            end;
           end
          else
           if pos('NUMBER',TableField.field_type)>0 then
            begin
             TableField.Ed:=TSpinEdit.Create(InputParent);
             with TSpinEdit(TableField.Ed) do
              begin
//Задаю свойства
               if visible_field then top_offset:=25;

              end;
            end
           else
            if pos('DATE',TableField.field_type)>0 then
             begin
              TableField.Ed:=TMaskEdit.Create(InputParent);
              with TMaskEdit(TableField.Ed) do
               begin
//Задаю свойства
                if visible_field then top_offset:=25;
               end;
             end
            else
             begin
              //BLOB
              TableField.Ed:=TEdit.Create(InputParent);
              with TEdit(TableField.Ed) do
               begin
                if visible_field then top_offset:=25;
//Задаю свойства
               end;
              end;
         if visible_field then
          begin
           TableField.Lab:=TLabel.Create(InputParent);
            with TableField.Lab do
             begin
//Задаю свойства
             end;
          end;
         with TableField.Ed do
          begin
           Name:=TableField.field_name;
           Left:=230;
           Top:=top_value;
           if visible_field then top_value:=top_value+top_offset;
           Parent:=InputParent;
           Visible:=visible_field;
          end;
         InputParent.Height:=top_value+20;
         Add(TableField);
        end;
      finally
       sections.Free;
       //ShowMessage(res);
      end;
     end;
   end;
 finally
  IniFile.Free;
 end;
end;


Код читает ини-файл выбирает свойства обьектов и зоздает форму для ввода. Все это работает.
Я в главной форме двумя кнопками создаю обьекты з разными параметрами:
Код

procedure TMainForm.BtnObjektClick(Sender: TObject);
begin
if MainTableForm<>nil then MainTableForm.free;
MainTableForm:=FMainTableForm.Create(MainForm,'T_Objekt',False);
end;

procedure TMainForm.BtnOsobaClick(Sender: TObject);
begin
if MainTableForm<>nil then MainTableForm.free;
MainTableForm:=FMainTableForm.Create(MainForm,'T_Osoba',True);
end;


если я жму на кнопки на основной форме, даже по несколько раз - формы переключаються или пеперисовываються и как-будто все нормально, но если я нажимаю на кнопку которую создал в класе SaveButtonClick - форма исчезает (ну да, так задуманно) но при клике на кнопках для создания вилетает Инвалид Поинтер Оператион. Очень прошу помочь!
PM MAIL   Вверх
Rennigth
Дата 19.3.2010, 19:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1708
Регистрация: 21.6.2004
Где: Moscow

Репутация: 15
Всего: 76



1. 
Код

procedure TMainForm.BtnObjektClick(Sender: TObject);
begin
if MainTableForm<>nil then MainTableForm.free;
MainTableForm:=FMainTableForm.Create(MainForm,'T_Objekt',False);
end;

procedure TMainForm.BtnOsobaClick(Sender: TObject);
begin
if MainTableForm<>nil then MainTableForm.free;
MainTableForm:=FMainTableForm.Create(MainForm,'T_Osoba',True);
end;

Кто тебе сказал что при втором нажатии на кнопки MainTableForm будет nil? Если и хочешь постоянно пересоздавать то уничножай объект или процедурой FreeAndNil или явно обнуляй указатель.


2. Странный у тебя деструктор списка какой-то...
Код

destructor CTableFieldCollecton.Destroy;
var i:cardinal;
begin
 for i := 0 to Count - 1 do
  Items[i].Destroy;
 inherited;
end;


Кто сами Item-ы будет удалять из списка? лжно это выглядеть примерно так:
Код

destructor CTableFieldCollecton.Destroy;
var 
  i: cardinal;
begin
  for i := Count - 1 downto 0 do
    Items[i].Remove;
  inherited;
end;

А св-во OwnsObjects при создании выставить в True.





--------------------
(* Honesta mors turpi vita potior *)
PM MAIL ICQ   Вверх
RomanEEP
Дата 19.3.2010, 20:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 424
Регистрация: 18.5.2006
Где: Коломна

Репутация: 1
Всего: 8



AlexLogos, я думаю можно на ты и без формальностей
В коде
if MainTableForm<>nil then MainTableForm.free;
MainTableForm - это указатель на объект, это простое число которое означает адрес в оперативной памяти в котором находится объект
если это число равно нулю, значит указатель не указывает ни на какой объект
объект - это блок данных, в котором хранятся поля(переменные) этого объекта 
на один объект может быть неограниченное количество указателей

метод Free объекта удаляет блок данных из памяти. При этом ни один указатель на объект НЕ ИЗМЕНЯЕТСЯ, не устанавливается в 0, потому что на один объект может быть множество указателей, о которых он знать не может. Повторное вызов любого метода этого класса, втч Free может вызвать различные ошибки обращения к памяти, т.к. на том месте куда указывает указатель ничего нет.

Поэтому, чтобы запомнить что объект, на который указатель указывает больше не существует следует его установить в 0 принудительно
Код

  MainTableForm.free;
  MainTableForm := nil;


Правда если в MainTableForm.free; возникнет исключительня ситуация, то объект будет частично уничтожен (к нему больше обращаться нельзя, а указатель не будет установлен в 0. Чтобы этого избежать лучше воспользоваться функцией FreeAndNil(); из SysUtils - она сперва установит указатель в 0, а затем вызовет деструктор

Добавлено через 2 минуты и 12 секунд
Цитата(Rennigth @  19.3.2010,  19:58 Найти цитируемый пост)
Кто сами Item-ы будет удалять из списка? лжно это выглядеть примерно так:

сами итемы из списка удалятся в TObjectList.Destroy который вызовет TList.Destroy, который в свою очередь вызовет TList.Clear;
PM MAIL   Вверх
Rennigth
Дата 19.3.2010, 20:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1708
Регистрация: 21.6.2004
Где: Moscow

Репутация: 15
Всего: 76



Цитата(RomanEEP @  19.3.2010,  20:13 Найти цитируемый пост)
сами итемы из списка удалятся в TObjectList.Destroy который вызовет TList.Destroy, который в свою очередь вызовет TList.Clear; 

Все равно плохой тон... Если уж ручками уничтожаешь объекты, то не есть хорошо оставлять не валидные указатели, тем более это TObjectList и при выставленном OwnsObjects будет большой AV.


--------------------
(* Honesta mors turpi vita potior *)
PM MAIL ICQ   Вверх
AlexLogos
Дата 19.3.2010, 20:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 229
Регистрация: 23.4.2009

Репутация: нет
Всего: 1



Спасибо, попробую  smile 
PM MAIL   Вверх
AlexLogos
Дата 22.3.2010, 11:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 229
Регистрация: 23.4.2009

Репутация: нет
Всего: 1



Я немного изменил деструкторы, всюду в коде где удаляються обьекты вместо вызова Free вызываю FreeAndNil, таким образом уничтожаю обьекты в памяти и указатели на них - и все заработало! Огромное спасибо что помогли разобраться smile !
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Для новичков"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.1129 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.