PDA

View Full Version : فرمم بیشتر از 1 بار Create نشود



AbiriAmir
یک شنبه 17 آبان 1388, 16:06 عصر
سلام
من یه MDIForm دارم
از داخلش یه سری فرم هایی که MDIChild هستن رو Create میکنم.
اونوقت onClose اون فرم ها هم اونا رو Free کردم
حالا اگه روی دکمه ای که فرم 2 رو میسازه 2 بار کلیک کنن 2 بار فرمه ساخته میشه ولی با بستن یکی از اونا برنامه فکر میکنه که دیگه اون فرم وجود نداره و با بستن دوباره همون فرم با ارور Access Violation مواجه میشم که البته اگه با PostMessage اونا رو ببندم این ارور رو نمیده.
بعضی موقع ها هم Abstract error میده.
این ارور دومی دیگه مال چیه؟
من فکر کردم اگه یه کاری کنم که هر فرمی بیشتر از یه بار ساخته نشه مشکل حله ولی نمیدونم چجوری اینکار رو بکنم

Felony
یک شنبه 17 آبان 1388, 17:05 عصر
شما با 2 بار کلیک 2 بار فرم رو نمیسازید ، وقتی فرم به صورت زیر ساخته میشه چه طور با 2 بار کلیک 2 تا ساخته میشه در صورتی که یک شئ از کلاس TFrom مشتق کردید ؟

Var
Test:TForm;
begin
Test:=TFrom.Create;
end;


شما با کد زیر :

begin
Test.Free;
end;
در حقیقت فضای اشغال شده توسط اون فرم در حافظه رو آزاد میکنید ، پس تا اینجا اگر 100 بار روی دکمه ی ساخت فرم کلیک کنید 1 فرم که در اینجا Test هست ساخته میشه ، حالا با کلیک بر روی دکمه ی Free فضای اون رو از حافظه آزاد میکنید ، با کلیک دوباره بر روی دکمه Free برنامه میبینه شئ با نام Test در حافظه موجود نیست و پبغام خطا دریافت میکنید .

برای حل این مشکل قبل از آزداد سازی یک شئ اول ببین اون شئ وجود داره یا نه بعد آزادش کن ، یا میتونی یک متغیر منطقی در نظر بگیری در زمان ساخت شئ به اون مقدار True بدی و بعد موقع آزاد سازی چک کنی اگر True بود شئ رو آزاد کنی و اون متغیر رو False ، البته شاید راه بهتری هم وجود داشته باشه که من الان به ذهنم نمیرسه .

موفق باشید .

AbiriAmir
یک شنبه 17 آبان 1388, 20:19 عصر
راه خوبیه ولی حالا تو یکی دیگه از فرم هام حتی وقتی 2 تا از اون رو باز نمیکنم، وقتی میبندمش Abstract Error میده
اولین باره که با این ارور مواجه میشم
در ضمن من از کد زیر برای ساختن فرم ها استفاده میکنم:
[CODEApplication.CreateForm(TForm2, Form2);[/CODE]

alinikaein
یک شنبه 17 آبان 1388, 20:41 عصر
سلام.

فكر كنم اگه از كد زير استفاده كني، بد نباشه:

جهت ساخت:



if not Assigned(MyForm) then
MyForm := TMyForm.Create(Application);
براي آزاد سازي هم:



if Assigned(MyForm) then
FreeAndNil(MyForm);
فكر كنم با اين كارها، مشكلت حل بشه ان‌شاءالله

AbiriAmir
یک شنبه 17 آبان 1388, 20:41 عصر
آهان
به یه نتایجی رسیدم
وقتی تو فرم 2 که یه MDIChild هست مستقیم میزنم close و تو onCloseش فرم 2 رو Free کرده Abstract Error میده ولی وقتی میزنم Form2.Close دیگه اون ارور رو نمیده { ولی Access Violation میده }
در ضمن این دفعه من 2 بار هم بازش نکردم
1 بار بازش کردم
ولی وقتی با دکمه ضربدر ویندوز میبندمش یا postmessage میکنم ارور نمیده ولی وقتی میزنم form2.close ارور میده
چیکار کنم؟؟؟
:عصبانی++::گریه: :عصبانی++::گریه: :عصبانی++::گریه: :عصبانی++::گریه: :عصبانی++::گریه:

AbiriAmir
یک شنبه 17 آبان 1388, 20:47 عصر
سلام.

فكر كنم اگه از كد زير استفاده كني، بد نباشه:

جهت ساخت:



if not Assigned(MyForm) then
MyForm := TMyForm.Create(Application);
براي آزاد سازي هم:



if Assigned(MyForm) then
FreeAndNil(MyForm);
فكر كنم با اين كارها، مشكلت حل بشه ان‌شاءالله

Access violation

tdkhakpur
یک شنبه 17 آبان 1388, 20:53 عصر
برای حل این مشکل قبل از آزداد سازی یک شئ اول ببین اون شئ وجود داره یا نه بعد آزادش کن ، یا میتونی یک متغیر منطقی در نظر بگیری در زمان ساخت شئ به اون مقدار True بدی و بعد موقع آزاد سازی چک کنی اگر True بود شئ رو آزاد کنی و اون متغیر رو False ، البته شاید راه بهتری هم وجود داشته باشه که من الان به ذهنم نمیرسه .

و مهمترين مساله براي اجراي موارد فوق اينه كه متغيير از نوع فرم را حتما بايد از نوع گلوبال تعرف كنيد نه لوكال.
ولي شما براي نمايش فرم ميتوانيد از متد زير استفاده كنيد كه اجازه دو بار كليك را براي شما ندهد.


Form1.ShowModal;

دليل اينكه شما داخل به هنگام free كردن دچار خطا ميشويد به خاطر اين هست كه شما از يك آدرس چندين بار تقاضاي free شدن ميكنيد و اگر شما متغيير فرم را داخل event تعريف كنيد اين خطا حذف خواهد شد.

vcldeveloper
یک شنبه 17 آبان 1388, 23:43 عصر
دليل اينكه شما داخل به هنگام free كردن دچار خطا ميشويد به خاطر اين هست كه شما از يك آدرس چندين بار تقاضاي free شدن ميكنيد
متد Free در صورتی که شی مربوطه قبلا آزاد شده باشه، یا nil باشه، Access Violation برنمیگردانه. علت اصلی اینکه گفته میشه بجای Destroy از Free استفاده بشه، همین هست.

Mahmood_M
دوشنبه 18 آبان 1388, 00:29 صبح
در حالت عادی وقتی یک MDIChild ساخته میشه و اگر در رویداد OnClose اون Action این رویداد رو برابر با caFree کنید مشکلی برای بسته شدن فرم به وجود نمی یاد و به راحتی بسته و Free میشه ...
یک متغیر Global ( در قسمت Var اصلی یونیت ) تعریف کنید مثلا با نام F2 و از نوع TForm2 ( نام فرم Child ) ، هرجایی که خواستید ، اون رو Create کنید :

F2 := TForm2.Create(Application);
برای بستنش هم از دستور Close استفاده کنید :

F2.Close;

اگه میخواید کل فرمهای Child رو ببندید به صورت زیر عمل کنید :
procedure TForm1.BitBtn2Click(Sender: TObject);
var
I : Integer;
begin
for I := 0 to MDIChildCount - 1 do
MDIChildren[I].Close;
end;
MDIChildCount تعداد فرمهای Child رو برمیگردونه و MDIChildren هم با گرفتن یک عدد فرم Child ای که Index اش برابر اون عدد هست رو برمی گردونه ...

برای بستن از کد زیر هم می تونید استفاده کنید :

ActiveMDIChild.Close;
ActiveMDIChild به فرم MDI فعال اشاره می کنه ...
در کل منظور اینه که برای بستن یک فرم Child دستور Close کافیه ، به شرطی که در رویداد OnClose اون Action رو برابر با caFree قرار بدید ...
برای این که فقط یک بار فرمتون رو Create کنید می تونید یک متغیر عمومی مثلا با نام Created از نوع Boolean ایجاد کنید و وقتی فرم رو می سازید اون رو True کرده و وقتی می بندید اون رو False کنید و در هنگام Create فرم هم چک کنید که اگر متغیر False بود فرم رو Create کنید ...

فکر می کنم در ساخت فرمها اشتباه دارید ...
لطفا بگید که دقیقا قصدتون چیه ... ؟ شاید راه حلی پیدا شد و مجبور نشدید فقط یک بار فرمتون رو Create کنید ... ، همیشه راه حل بهتری هست ...

موفق باشید ...

AmirSky
دوشنبه 18 آبان 1388, 19:40 عصر
روشی رو که alinikaein گفته اگه اجرا کنی جواب می ده ساده و مطمئن است
روشی رو که Mahmood_N گفته من چند سالی است که استفاده می کنم و مشکلی اصلا نداره بغیر از اینکه یکم کار رو زیاد می کنه
من از این روش استفاده می کنم:

در قسمت public فرم اصلی تعریف متغیر FrmForm1Created : Boolean



if FrmForm1Created = True then
begin
FrmForm1Created.BringToFront;
abort;
end
else FrmForm1 := TFrmForm1.Create(Application



برای اینکه وقتی فرم اگر ایجاد بود روی تمام فرم های باز قرار گیرد از BringToFront استفاده می کنم.

در قسمت OnClose فرم اصلی برای اینکه حتما فرم های باز Free شوند از


if FrmForm1Created = True then FrmForm1.Close


در FormCreate فرم مورد نظر


frmMain.FrmForm1Created := True;


در FormClose فرم مورد نظر


frmMain.FrmForm1Created := False;
Free;

AbiriAmir
سه شنبه 19 آبان 1388, 16:20 عصر
جناب MahmoodN از شما تشکر میکنم
با یک خط کارم راه افتاد و اون هم خط زیر بود:

Action := CaFree;
جناب کشاورز باید بگم که این مشکل توی یکی از فرم هام طوری بود که حتی اگه قبلا Free هم نشده بود ارور میداد

در ضمن چه فرقی بین روش های ساختن فرم زیر وجود داره؟


Application.CreateForm(TX, X);

و


X : TX.Create(Application);

البته یه فرق ضاهریش اینه که تو روش دومی دیگه با دکمه ضربدر فرم بسته نمیشه. اینطور نیست؟

vcldeveloper
سه شنبه 19 آبان 1388, 18:22 عصر
در ضمن چه فرقی بین روش های ساختن فرم زیر وجود داره؟
فرقشون در این هست که CreateForm بررسی میکنه آیا فرم اصلی برای برنامه تعریف شده یا نه، اگر نه، فرم مربوطه را به عنوان فرم اصلی برنامه میسازه.