Передача данных между формами
У меня есть 3 формы(2 и 3 формы - Available forms), на каждой по кнопке.При нажатии на кнопку строится последующая форма с передачей данных из предыдущей. Из 1 во 2 всё передаётся, а вот из 2 в 3 не как. Пишет ошибку доступа к памяти.
Вопрос глупый, прошу простить ещё раз, не как не могу вспомнить как это решается.:confused:
Простенький наглядный пример:
Вызов 2 формы из 1;
{
TForm2 *Form2=new TForm2(Form1);
Form2->Show();
}
Приём во 2 форме
: TForm(Owner)
{
Label1->Caption=Form1->Edit1->Text;
Edit1->Text=Form1->Label1->Caption;
}
Вызов 3 формы
{
TForm3 *Form3;
Application->CreateForm(__classid(TForm3), &Form3);
Form3->Show();
}
Приём в 3 форме:
: TForm(Owner)
{
Label1->Caption=Form2->Edit1->Text;
Edit1->Text=Form2->Label1->Caption;
}
Ответ то простой, нужно формы объявлять не в теле функции.
А в заголовке файла, как глобальные объекты.
Прошу прощения за такой казус :p
P.S. Если есть ещё какие варианты буду рад увидеть )))))
{
TForm3 *Form3;
Application->CreateForm(__classid(TForm3), &Form3);
Form3->Init(Form2->Edit1->Text, Form2->Label1->Caption);
Form3->Show();
}
...
__fastcall TForm3::Init(AnsiString s1, AnsiString s2)
: TForm(Owner)
{
Label1->Caption=s1;
Edit1->Text=s2;
}
синтаксис может хромать
Ответ то простой, нужно формы объявлять не в теле функции.
А в заголовке файла, как глобальные объекты.
Никто не запрещает их объявлять в теле метода. Это даже очень хорошо когда их там можно объявить.
Никто не запрещает их объявлять в теле метода. Это даже очень хорошо когда их там можно объявить.
не забывайте о мемори ликах
конечно имелись в виду применения вида
Form3->Init(Form2->Edit1->Text, Form2->Label1->Caption);
Form3->ShowModal();
delete Form3;
накорябал я там только для "типа того". Хоть к формам все равно будет доступ через Application->Components[], это не тру.
Извиняюсь, не силён в терминалогии. А что такое мемори лики?
Это "русское слово" для memory leaks. Вкратце, если ты создаёшь объект в какой-то функции, и этот объект используется только в ней, но ты при возвращении из неё не разрушаешь объект, то он, хоть и неиспользуемый, всё равно продолжает занимать память. => memory leak.
Иными словами:
Create - Use - Destroy или Allocate - Use - Free
Последний пункт часто забывается (см. пост Phodopus), и память остаётся висеть не нужная, но и не освобождённая.
Другое дело, что обычно размер такой памяти (если говорить об объектах) очень небольшой, и на современных компах с парой гигов оперы это не сильно скажется, тем более, что при завершении проги вся её память освобождается в любом случае.
Но всё равно нужно писать правильно.
Небольшое уточнение. Если объект просто создается, например:
mc.SomeFunc();
- то он, разрушается при выходе из функции - как и простые типы данных. Никаких утечек памяти не будет. И в большинстве случаев, заботится о очистке памяти не надо - это происходит потому, что память выделяется на этапе компиляции.
Собственно memory leak возможен только тогда, когда память под объект выделяется в "куче" (heap) - т.е. динамически, и на эту область создается указатель.
mc->SomeFunc();
...
delete mc;// должно быть обязательно!!!!
Потому что по выходе из функции - указатель тоже разрушается (!!!) (выходит из области видимости). А выделенная память - не может быть очищена - ведь указатель на нее потерян. Во многих высокоуровневых языках существуют так называемые "сборщики мусора" - их задача отслеживать указатели, которые не нужны и очищать память. В С++ эту роль играют "умные указатели" - например шаблон auto_ptr и т.п. - надо либо обязательно использовать его, либо явно вызывать delete
Другое дело, что обычно размер такой памяти (если говорить об объектах) очень небольшой, и на современных компах с парой гигов оперы это не сильно скажется, тем более, что при завершении проги вся её память освобождается в любом случае
На самом деле, рассчитывать на это не стоит. Размер объекта (особенно если это форма) может оказаться для вас весьма неожиданно большим - и пару вызовов могут зачастую "положить" систему либо аварийно завершить программу.
Кстати, советую помнить что все компоненты создаются ТОЛЬКО ДИНАМИЧЕСКИ!!! (форма - это тоже компонент). Поэтому память надо чистить всегда.
Но BCB предоставляет для этого два способа - использование delete и использование события формы OnClose. Можно использовать либо одно, либо другое.
Пример как использовать OnClose есть в экзеплах самого билдера и на форуме.
Тут кстате ещё один вопросик на засыпку небольшой по поводу передачи данных и форм.
В общем в мне необходимо создать объект и для ввода данных я создаю отдельную форму, с которой потом данные передаются в создаваемый объект.Объекты собираются в вектор.
Вопрос такой: как лучше это сделать?
Вариант 1: (рабочий, но некрасивый)
void __fastcall ControlCardClass::NewParameter(TObject *Sender){
TForm5* Form5;
Application->CreateForm(__classid(TForm5), &Form5);
if(Form5->ShowModal()==mrOk){
if (!ParameterList.empty()) StrGrid1->RowCount=StrGrid1->RowCount+1;
ParameterList.push_back(Form5->returnParameter());
StrGrid1->Cells[0][ParameterIndex+1]=ParameterIndex+1;
StrGrid1->Cells[1][ParameterIndex+1]=ParameterList[ParameterIndex]->Name;
StrGrid1->Cells[2][ParameterIndex+1]=ParameterList[ParameterIndex]->Unit;
StrGrid1->Cells[3][ParameterIndex+1]="от "+FloatToStr(ParameterList[ParameterIndex]->LSL)+
" до "+FloatToStr(ParameterList[ParameterIndex]->USL);
StrGrid1->Cells[4][ParameterIndex+1]=ParameterList[ParameterIndex]->Note;
ParameterIndex++;
}
delete Form5;
}
void __fastcall TForm5::OkClick(TObject *Sender)
{
if(EditName->Text==""){ShowMessage("Не введено имя параметра");}
else{ Parameter=new ParameterClass();
if (EditName->Text!=""){Parameter->Name=EditName->Text;}
if(EditUnit->Text!=""){Parameter->Unit=EditUnit->Text;}
if(SpinEdit->Text!=""){Parameter->QuantitySigns=StrToInt(SpinEdit->Text);}
if(EditMin->Text!=""){Parameter->minValue=StrToFloat(EditMin->Text);}
if(EditMax->Text!=""){Parameter->maxValue=StrToFloat(EditMax->Text);}
Parameter->CheckCondition=CheckCondition->Checked;
if(EditUSL->Text!=""){Parameter->USL=StrToFloat(EditUSL->Text);}
if(EditLSL->Text!=""){Parameter->LSL=StrToFloat(EditLSL->Text);}
if(EditSL->Text!=""){Parameter->SL=StrToFloat(EditSL->Text);}
if(EditTop->Text!=""){Parameter->topBorder=StrToFloat(EditTop->Text);}
if(EditBottom->Text!=""){Parameter->bottomBorder=StrToFloat(EditBottom->Text);}
if(EditNote->Text!=""){Parameter->Note=EditNote->Text;}
}
}
Второй вариант: (более красивый, но не знаю как доделать)
В конструкторе класса вызывать форму и всё вводить,но тогда не понятно как узнать был создан объект или нажата отмена(при отмене он всё равно создаст объект тока пустой)
void __fastcall ControlCardClass::NewParameter(TObject *Sender){
ParameterList.push_back(new ParameterClass());
}
class ParameterClass{
public:
String Name;
String Note;
String Unit;
int QuantitySigns;
float minValue,maxValue;
boolean CheckCondition;
float USL,SL,LSL;
float topBorder,bottomBorder;
ParameterClass();
};
ParameterClass::ParameterClass(){
TForm5 *Form5;
Application->CreateForm(__classid(TForm5), &Form5);
Form5->ShowModal();
if(Form9->ShowModal()==mrOk){
if(Form5->EditName->Text!=""){Name=Form5->EditName->Text;}
if(Form5->EditUnit->Text!=""){Unit=Form5->EditUnit->Text;}
if(Form5->SpinEdit->Text!=""){QuantitySigns=StrToInt(Form5->SpinEdit->Text);}
if(Form5->EditMin->Text!=""){minValue=StrToFloat(Form5->EditMin->Text);}
if(Form5->EditMax->Text!=""){maxValue=StrToFloat(Form5->EditMax->Text);}
CheckCondition=Form5->CheckCondition->Checked;
if(Form5->EditUSL->Text!=""){USL=StrToFloat(Form5->EditUSL->Text);}
if(Form5->EditLSL->Text!=""){LSL=StrToFloat(Form5->EditLSL->Text);}
if(Form5->EditSL->Text!=""){SL=StrToFloat(Form5->EditSL->Text);}
if(Form5->EditTop->Text!=""){topBorder=StrToFloat(Form5->EditTop->Text);}
if(Form5->EditBottom->Text!=""){bottomBorder=StrToFloat(Form5->EditBottom->Text);}
if(Form5->EditNote->Text!=""){Note=Form5->EditNote->Text;
}
delete Form5;
}
Просто по моему гораздо удобней было бы если форма вызывалась при создании объекта в его конструкторе. При таком раскладе просто не надо было писать функцию для возвращения объекта с формы. Да и по моему красивее было бы.
Может конечно это нериально, но можно как то сделать так чтобы конструктор не создавал объект.
Просто щас получается что я сначало создаю форму, потом при нажатии в ней ОК объект, заполняю его, возвращаю в основную форму и там его запихиваю в вектор если опять нажата ОК на той форме - по моему это немного неправильно и долго.
Может конечно это нериально, но можно как то сделать так чтобы конструктор не создавал объект.
Просто щас получается что я сначало создаю форму, потом при нажатии в ней ОК объект, заполняю его, возвращаю в основную форму и там его запихиваю в вектор если опять нажата ОК на той форме - по моему это немного неправильно и долго.
А зачем вам заполнять объект в созданной форме?
Заполняйте его там же, где вы ее создаете. Вам вовсе не надо передавать его туда и обратно.