C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
Удаление динамически созданных объектов, как реализовать удаление
** Николай
Отправлено: 04.05.2006, 14:55


Не зарегистрирован







Встала такая задача:
Во время работы программы на форме создаются компоненты типа TLabel. Затем нам необходимо их удалить.
Имена создаются так Label1, Label2 и т.д.
Помогите как мне реализовать цикл чтоб удалить все созданные объекты???
Valdemar
Отправлено: 04.05.2006, 15:55


Мастер участка

Группа: Участник
Сообщений: 433



Когда создаете динамические объекты сохраняйте указатели на них в списке. А при удалении берите указатели из списка и удаляйте объекты.
Guest
Отправлено: 05.05.2006, 12:14


Не зарегистрирован







Что то ошибку выдает не пойму почему:
Делаю так
в h файле прописываем
TList *TListLsbel;

//---------Динамическое создание надписей---------------------------------------
TLabel *E = new TLabel(Form1->Image1);
E->Parent = Form1;
E->Top=Form1->Ytext+10; E->Left=Form1->Xtext-1;
E->Visible=true;
E->Enabled=true;

if(Form4->Edit1->Text != "")
E->Caption = Form4->Edit1->Text;
else
E->Caption = "???";

E->Name = "Label" + IntToStr(Form1->index);
E->Font->Color = clBlack;
E->Height = 20;
E->Transparent = true;
Form1->LabelList->Add(*E);
E->OnClick = Form1->EOnClick;

Когда создаю надпись вылетает ошибка обращения по аресу...
** Николай
Отправлено: 05.05.2006, 12:18


Не зарегистрирован







выше мое...
Doga
Отправлено: 05.05.2006, 14:30


Мастер участка

Группа: Участник
Сообщений: 575



В предпоследней строке кода:
CODE

Form1->LabelList->Add(E);


Если Form1->LabelList это TList, то * перед E ставить не надо, ведь переменная E у Вас и так обьявлна как указатель на класс TLabel.

А для Form1->LabelList Вы конструктор вызываете?

И почему у метки разные владелец и родитель?

Отредактировано Doga — 05/05/2006, 14:38
Guest
Отправлено: 10.05.2006, 12:47


Не зарегистрирован







А для Form1->LabelList Вы конструктор вызываете?

И почему у метки разные владелец и родитель?


1) А можно поподробнее, что должен содержаить конструктор в данном случае??

2) Если ставлю родителя такого же, т.е. Form1->Image1, то не работает, пишет что Cannot convert TImage to TWinControl.
Guest
Отправлено: 10.05.2006, 14:42


Не зарегистрирован







1. Конструктор надо просто вовремя вызвать, т.е. до использования объекта:
CODE

Form1->LabelList = new TList();


2.Владельцем и родителем метки сделайте Form1. А зачем для этого Вы пытаетесь использовать Form1->Image1?
** Николай
Отправлено: 11.05.2006, 11:01


Не зарегистрирован







Списки заработали, но на ум пришел более короткий вариант:
По нажатии на объекте мышкой его надо удалять, реализовал так:

void __fastcall TForm1::EOnClick(TObject *Sender)
{
if(Form3->SpeedButton6->Down == true)
{
Del = new TObject;
Del = Sender;
delete Del;
index--;
};
}

Del объявлен как TObject *Del;
Первый раз удаляет нормально, но при повторном удалении
выдает ошибку обращения по адресу, что такое не пойму....
Guest
Отправлено: 11.05.2006, 11:10


Не зарегистрирован







Del = new TObject; // А кто это будет удалять?
Del = Sender;
delete Del;
** Николай
Отправлено: 11.05.2006, 11:48


Не зарегистрирован







Кажется начинаю доходить. Получается как бы зависший указатель???
А как тогда поступить??? Напрямую удалить указатель на объект на котором кликнули я ведь не могу:(
Asher
Отправлено: 11.05.2006, 12:19


Мастер участка

Группа: Модератор
Сообщений: 550



QUOTE
Напрямую удалить указатель на объект на котором кликнули я ведь не могу:(

Можете.
delete Sender;
** Николай
Отправлено: 11.05.2006, 12:37


Не зарегистрирован







Извиняюсь конечно, но не могу на самом деле, выдает ошибку вот такую:
access violation at adress 00494FDC in module 'Project1.exe'. Read of adress BAADF00D.
Вот код создания по щелчку мыши:

TLabel *E = new TLabel(Form1);
E->Parent = Form1;
E->Top=Form1->Ytext+10; E->Left=Form1->Xtext-1;
E->Visible=true;
E->Enabled=true;

if(Form4->Edit1->Text != "")
E->Caption = Form4->Edit1->Text;
else
E->Caption = "???";

E->Name = "Label" + IntToStr(Form1->index);
E->Font->Color = clBlack;
E->Height = 20;
E->Transparent = true;
E->OnClick = Form1->EOnClick;
Form4->Visible = false;

Вот удаление:

void __fastcall TForm1::EOnClick(TObject *Sender)
{
if(Form3->SpeedButton6->Down == true) // Если режим удалять
{
delete Sender;
index--;
}; // индекс для создания подписей уменьшаем на 1
}

Вообщем не работает:((
** Николай
Отправлено: 11.05.2006, 12:39


Не зарегистрирован







Извиняюсь конечно, но не могу на самом деле, выдает ошибку вот такую:
access violation at adress 00494FDC in module 'Project1.exe'. Read of adress BAADF00D.
Вот код создания по щелчку мыши:

TLabel *E = new TLabel(Form1);
E->Parent = Form1;
E->Top=Form1->Ytext+10; E->Left=Form1->Xtext-1;
E->Visible=true;
E->Enabled=true;

if(Form4->Edit1->Text != "")
E->Caption = Form4->Edit1->Text;
else
E->Caption = "???";

E->Name = "Label" + IntToStr(Form1->index);
E->Font->Color = clBlack;
E->Height = 20;
E->Transparent = true;
E->OnClick = Form1->EOnClick;
Form4->Visible = false;

Вот удаление:

void __fastcall TForm1::EOnClick(TObject *Sender)
{
if(Form3->SpeedButton6->Down == true) // Если режим удалять
{
delete Sender;
index--;
}; // индекс для создания подписей уменьшаем на 1
}

Вообщем не работает:((
Asher
Отправлено: 11.05.2006, 13:20


Мастер участка

Группа: Модератор
Сообщений: 550



Что значит не работает?
Удаляет? Удаляет. wink.gif
Это сообщение об ошибке появляется в результате обработки следующего кода:
QUOTE
procedure TControl.DoMouseUp(var Message: TWMMouse; Button: TMouseButton);
begin
 if not (csNoStdEvents in ControlStyle) then
   with Message do MouseUp(Button, KeysToShiftState(Keys), XPos, YPos);
end;

procedure TControl.WMLButtonUp(var Message: TWMLButtonUp);
begin
 inherited;
 if csCaptureMouse in ControlStyle then MouseCapture := False;
 if csClicked in ControlState then
 begin
   Exclude(FControlState, csClicked);
   if PtInRect(ClientRect, SmallPointToPoint(Message.Pos)) then Click;
 end;
 DoMouseUp(Message, mbLeft);
end;

в Click происходит вызов пользовательского OnClick
после него происходит вызов DoMouseUp. Там ничего нет и ошибка возникает просто при чтении полей несуществующего объекта.
Это неприятно, но в крайнем случае можно пережить. cool.gif
Но лучше все равно так не делать.
Guest
Отправлено: 11.05.2006, 13:32


Не зарегистрирован







В вашем случае при клике указатель на удаляемый Label используется вызывающей функцией и, следовательно, указывает на мусор.
Нужна функция "сборки мусора". Можно сделать так.
CODE

//---------------------------------------------------------------------------

void __fastcall TForm1::Bt_DynLabelClick(TObject *Sender)
{
static int labNN = 0;

labNN++;
TLabel *E = new TLabel(Label0->Owner);
E->Parent = Label0->Parent;
E->Name = "Label" + AnsiString(labNN);
E->Top  = Label0->Top + 18 * labNN;
E->Left = Label0->Left;
E->Visible = true;
E->Enabled = true;

E->Caption = E->Name;
E->OnClick = Label0->OnClick;
}
//---------------------------------------------------------------------------

#define My1_NOTIFY      (WM_APP+101)

//---------------------------------------------------------------------------

void __fastcall TForm1::Label0Click(TObject *Sender)
{
TLabel *lbl = dynamic_cast<TLabel*>(Sender);
if (!lbl || lbl == Label0)      return;
PostMessage(this->Handle, My1_NOTIFY, 0, int(Sender));
}

//---------------------------------------------------------------------------

//protected:
//      virtual void __fastcall WndProc (Messages::TMessage &Message);

void __fastcall TForm1::WndProc (Messages::TMessage &Message)
{
switch(Message.Msg)
{  case My1_NOTIFY:
       if (Message.WParam == 0)
        {  TLabel *lbl = dynamic_cast<TLabel*>((TObject*)Message.LParam);
           if (lbl) delete lbl;
        }
       break;

   default:
       TForm::WndProc(Message);
       break;
}
}

//---------------------------------------------------------------------------

xTrim
Отправлено: 11.05.2006, 21:19


Машинист паровоза

Группа: Участник
Сообщений: 208



Будьте проще господа smile.gif
CODE

int LabelCount = 0;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
this->OnMouseUp = FormMouseUp; // это для ясности просто
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseUp(TObject *Sender, TMouseButton Button,TShiftState Shift, int X, int Y)
{
TLabel* E = new TLabel(this);
E->Parent = this;
E->Left = X;
E->Top = Y;
E->Caption = "Label"+IntToStr(++LabelCount);
E->OnMouseUp = LabelMouseUp;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::LabelMouseUp(TObject *Sender, TMouseButton Button,TShiftState Shift, int X, int Y)
{
delete Sender;
LabelCount--;
}

** Николай
Отправлено: 16.05.2006, 13:19


Не зарегистрирован







Спасибо, за советы именно так и сделал, а точнее удаление по событию MouseUp, все отлично работает.
Встал такой вопрос, если я использую списки указателей, как потом удалить объект по его указателю и убрать указатель из списка, судя по логике такой текст, но не работает:

if(ListLabel->Count != 0)
{
for(int in=0; in<=ListLabel->Count; in++)
{
delete ListLabel->Items[in];
ListLabel->Delete(in);
};
};
CyberMind
Отправлено: 16.05.2006, 14:05


Ученик-кочегар

Группа: Участник
Сообщений: 29



Не работает наверно потому, что не существует элемента с индексом ListLabel->Count. Пиши
CODE
for(int in=0; in<ListLabel->Count; in++)
Doga
Отправлено: 16.05.2006, 14:20


Мастер участка

Группа: Участник
Сообщений: 575



CODE

void __fastcall TForm1::LabelMouseUp(TObject *Sender, TMouseButton Button,TShiftState Shift, int X, int Y)
{
int LabelIndex = ListLabel->IndexOf(Sender);

if (LabelIndex > -1)
{
ListLabel->Items[LabelIndex] = NULL;
ListLabel->Pack();
}

delete (TLabel *)Sender;
}


Отредактировано Doga — 16/05/2006, 14:21
** Николай
Отправлено: 16.05.2006, 14:25


Не зарегистрирован







Спасибо подправил, но ошибка совсем другая, а именно что то про обращение и чтение по адресу 0000000...
** Николай
Отправлено: 16.05.2006, 14:44


Не зарегистрирован







Спасибо Doga, но это уже немного другая задачка, а именно удаление всех Label`ов которые до этого были созданны динамически, казатели на которые нахоятся в списке.
CyberMind
Отправлено: 16.05.2006, 15:02


Ученик-кочегар

Группа: Участник
Сообщений: 29



Кинул на форму три Label.
Вот такой код добавляет их всех в список, удаляет Labels, удаляет их из списка, удаляет список
CODE
TList *ListLabel = new TList;
ListLabel->Add(Label1);
ListLabel->Add(Label2);
ListLabel->Add(Label3);
while(ListLabel->Count>0)
 {
  delete (TLabel *)ListLabel->Items[0];
  ListLabel->Delete(0);
 }
delete ListLabel;
** Николай
Отправлено: 16.05.2006, 15:10


Не зарегистрирован







Во все заработало, спасибо!!!!
Doga
Отправлено: 16.05.2006, 15:30


Мастер участка

Группа: Участник
Сообщений: 575



А я бы сделал бы по другому.

Если ListLabel больше не планируется исползовать:
CODE

...
for (int k  = 0; k < ListLabel->Count; k++)
{
  delete (TLabel *)ListLabel->Items[k];
}
delete ListLabel;
ListLabel = NULL;


А если он еще будет нужен:
CODE

...
for (int k  = 0; k < ListLabel->Count; k++)
{
  delete (TLabel *)ListLabel->Items[k];
  ListLabel->Items[k] = NULL;
}
ListLabel->Pack();



Так будет немного быстрее smile.gif
NILBOG
Отправлено: 26.12.2006, 05:59


Ученик-кочегар

Группа: Участник
Сообщений: 2



Господа помогите пожалуйста...
Допустим я создаю много лэйблов
типа
for(i=1;i<100;i++)
{
TLabel *Label = new TLabel(this);
Label->Parent=Form1;
}


Как их все удалить нажатием одной кнопки...ну очень надо! Спасибо!
Valdemar
Отправлено: 26.12.2006, 09:01


Мастер участка

Группа: Участник
Сообщений: 433



NILBOG, а вы предыдущие сообщения читали в этой теме? Сообщение перед вашим описывает удаление всех Label при условии, что указатели на них сохранены в списке.
NILBOG
Отправлено: 26.12.2006, 13:08


Ученик-кочегар

Группа: Участник
Сообщений: 2



QUOTE (Valdemar @ 26.12.2006, 09:01)
NILBOG, а вы предыдущие сообщения читали в этой теме? Сообщение перед вашим описывает удаление всех Label при условии, что указатели на них сохранены в списке.

А как сделать так чтобы динамические лэйблы были видимыми в других фунцкциях?
Valdemar
Отправлено: 26.12.2006, 16:22


Мастер участка

Группа: Участник
Сообщений: 433



Надо использовать список указателей на ваши label. Этот список должен иметь область видимости доступную для использующих его функций. Например, если функции глобальные, то и список должен быть глобальным, если функции являются методами какого-то класса, то и список может быть членом этого класса или глобальным.

Вернуться в Вопросы программирования в C++Builder