PDA

View Full Version : فرمهائی که در زمان اجرا Create می شوند



mzjahromi
دوشنبه 25 مهر 1384, 16:48 عصر
من بعضی از فرمهام رو زمان اجرا Create می کنم
مثلا اگر Form1 رو داشته باشم
هر وقت لازم داشتم این رو می نویسم


Application.CreateForm(TForm1,Form1);

حالا چطوری می تونم بفهمم که متغییر Form1 مقدار مجاز داره یا نه. یا به عبارتی Create شده یا نه

m-khorsandi
دوشنبه 25 مهر 1384, 17:27 عصر
درود
میتونید از تابع Assigned استفاده کنید.


if Assigned(Obj_Frm_DfnGoods) then

mzjahromi
دوشنبه 25 مهر 1384, 17:57 عصر
ممنون از راهنمائی تون

Naficy
سه شنبه 26 مهر 1384, 05:29 صبح
هنگام استفاده، توجه داشته باشید که تابع Assigned مقدار متغیر را با nil مقایسه می کند. و اگر nil نبود مقدار "درست" را بر می گرداند.

بنابراین اگر یه فرم Create کنید:
Form1:=TForm.Create(Application);
و بعد تخریبش کنید:
Form1.Free;
هنوز هم اگر Assigned رو صدا بزنید مقدار "درست" رو برمی گردونه.
برای حل این مساله، هنگام تخریب فرم (مثلا یا در رویداد FormDestroy یا در خود روال مخرب Destroy) متغیر فرم رو nil کنید:


procedure TForm1.FormDestroy(Sender: TObject);
begin
Form1 := nil;
end;

mzjahromi
سه شنبه 26 مهر 1384, 08:11 صبح
مرسی ولی می خوام اگه بشه نیاز به اون کار نباشه

m-khorsandi
سه شنبه 26 مهر 1384, 08:42 صبح
موردی که جناب نفیسی گفتند درسته،
معمولا" برای جلوگیری از اشتباه و آزاد کردن حافظه متغیر فرم رو Free و Nil میکنند.

vcldeveloper
چهارشنبه 27 مهر 1384, 02:35 صبح
برای اینکه فرمایش دوستان تکمیل بشه:
بجای اینکه کد بالا را در OnFormDestroy بنویسید؛ از FreeAndNil بجای Form1.Free استفاده کنید:


FreeAndNil(Form1);

Naficy
چهارشنبه 27 مهر 1384, 10:10 صبح
کد آقای کشاورز تقریبا در تمام موارد کار می کنه، ولی در موارد معدود و نادری ممکنه مشکل ساز باشه.
به طور خلاصه، اگر جای دیگه ای از برنامه، فرم free شود، ولی nil نشود این کد جواب نمی ده. مثل:
1 - خودتون یه جای دیگه ی برنامه یادتون رفته باشه از FreeAndNil استفاده کنین. (که خب خودتون می تونین درستش کنین!)
2 - Owner فرمتون اون رو free کنه. (معمولا Owner فرم رو شی Application معرفی می کنین. اگه این شی قبل از اجرای کد شما free بشه، باعث می شه که فرم هم free بشه ولی متغیرش nil نشود)
3 - هنگام بستن فرم در رویداد OnClose، کد Action:=caFree رو بذارین. که باز هم همین دردسر رو داره.

بنابراین پیشنهاد می کنم از همون روشی که گفتم استفاده کنین. یه خط کد که بیشتر نیست! نباید کار سختی باشه؟!

mzjahromi
چهارشنبه 27 مهر 1384, 13:41 عصر
ممنون از همگی

mzjahromi
چهارشنبه 27 مهر 1384, 13:51 عصر
ممنون از همگی

vcldeveloper
پنج شنبه 28 مهر 1384, 04:54 صبح
مواردی که ذکر کردید، مشکلی برای FreeAndNil بوجود نمیارند:

معمولا Owner فرم رو شی Application معرفی می کنین. اگه این شی قبل از اجرای کد شما free بشه، باعث می شه که فرم هم free بشه ولی متغیرش nil نشود
اگه Application آزاد بشه، کل برنامه از حافظه خارج میشه!

هنگام بستن فرم در رویداد OnClose، کد Action:=caFree رو بذارین.
حتی در صورت Free شدن کنترل، باز هم FreeAndNil درست عمل میکنه؛ اما دقت کنید که FreeAndNil جایگزین دو دستور زیر میشه:
Form1.Free;
Form1 := nil;
ولی Action:=caFree معمولا زمانی بکار برده میشه که زمان بسته شدن فرم مشخص نیست (بخصوص برای فرم های غیر Modal).
اگر می خواید بعد از ایجاد یک شی، عمل آزاد سازی آن بصورت خودکار صورت بگیره، می تونید اونو به یک Interface نسبت بدید و از خاصیت Reference-counting اینترفیس ها در دلفی استفاده کنید.

Naficy
جمعه 29 مهر 1384, 06:12 صبح
اگه Application آزاد بشه، کل برنامه از حافظه خارج میشه
فکر می کنم منظورتون اینه:
"اگر برنامه از حافظه خارج بشه، شی Application آزاد می شه."
کاملا درسته. اما در موارد واقعا نادری ممکنه کد تست بعد از آزاد شدن Application و قبل از اتمام برنامه صدا زده بشه. البته در برنامه نویسی های معمولی چنین اتفاقی نمی یفته و اگر کد تست را در جاهایی غیر از "کدهای پایانی" برنامه نوشته باشین می تونین مطمئن باشین مشکلی پیش نمی یاد.


حتی در صورت Free شدن کنترل، باز هم FreeAndNil درست عمل میکنه؛ اما دقت کنید که FreeAndNil جایگزین دو دستور زیر میشه:
Form1.Free;
Form1 := nil;
ولی Action:=caFree معمولا زمانی بکار برده میشه که زمان بسته شدن فرم مشخص نیست (بخصوص برای فرم های غیر Modal).
خوبه خودتون اشاره داشتین. وقتی کاربر خودش فرم رو می بنده و شما به صورت دستی اونو Free نمی کنین، و خود فرم اینکارو انجام می ده، متغیر فرم nil نمی شه. حتی اگر از درون فرم بخواین اونو free کنین (و بنابراین از متد Release استفاده کنین) بازهم وضعیت همینه.


صحبت من اینه که راهی که گفتم راه مطمئنه. یعنی امکان نداره خطا کنه. من می گم حتی اگه در یه وضعیت نادر احتمال خرابی برنامه بره باید ازش اجتناب کرد. (ضمنا ساده تر هم هست!)


------------------------------------------------------------------------------

اگر می خواید بعد از ایجاد یک شی، عمل آزاد سازی آن بصورت خودکار صورت بگیره، می تونید اونو به یک Interface نسبت بدید و از خاصیت Reference-counting اینترفیس ها در دلفی استفاده کنید.
بعید می دونم بشه با interface این کار رو کرد. جون در مورد شی صحبت می کنیم که ممکنه خودش نابود بشه. در واقع چیزی که نوشتین راه حل مساله ای برعکس مساله حاضره!!
ما در مورد nil شدن متغیر یک شی زمانی که free می شه صحبت می کنیم.
این راه شما برای free شدن شی زمانی که متغیرش nil می شه بدرد می خوره.
تفاوت این دوتا از زمین تا آسمونه....


------------------------------------------------------
در تکمیل بحث، یه راه دیگه استفاده از متد FreeNotification است. باید متد Notification رو هم سربارگذاری کنید. اما بقیه توضیح را نمی گم تا از راهنمای دلفی بخونین. (البته می دونم که مشکل دوستمون برطرف شده!!!!)

vcldeveloper
شنبه 30 مهر 1384, 01:47 صبح
فکر می کنم منظورتون اینه:
"اگر برنامه از حافظه خارج بشه، شی Application آزاد می شه."
خیر...شما اشاره کردید که:

معمولا Owner فرم رو شی Application معرفی می کنین. اگه این شی قبل از اجرای کد شما free بشه، باعث می شه که فرم هم free بشه ولی متغیرش nil نشود
اما منظور من این بود که وقتی Application آزاد بشه، کلا برنامه بسته میشه، پس نیازی نیست نگران کدهای بعد از آزاد شدن Application باشیم، چون این کدها فرصت اجرا شدن پیدا نمی کنند.

بعید می دونم بشه با interface این کار رو کرد. جون در مورد شی صحبت می کنیم که ممکنه خودش نابود بشه. در واقع چیزی که نوشتین راه حل مساله ای برعکس مساله حاضره!!
اگه دقت کنید من گفتم :

اگر می خواید بعد از ایجاد یک شی، عمل آزاد سازی آن بصورت خودکار صورت بگیره، می تونید اونو به یک Interface نسبت بدید
صحبتی از nil کردن متغیر آن شی نکردم، بلکه بحث من درباره آزادسازی خودکار آن شی توسط دلفی بود.

Naficy
شنبه 30 مهر 1384, 06:08 صبح
اما منظور من این بود که وقتی Application آزاد بشه، کلا برنامه بسته میشه، پس نیازی نیست نگران کدهای بعد از آزاد شدن Application باشیم، چون این کدها فرصت اجرا شدن پیدا نمی کنند.
و من هم تاکید کردم که می شه کدی نوشت که بعد از آزادسازی Application اجرا بشه.
ضمنا چند تا مثال حقیقی از زمانهایی که FreeAndNil مشکل پیدا می کنه زده ام و اینهمه بحث روی Application بیفایده است. (البته من مشکلی نمی بینم اگه بخوایم ادامه بدهیم. من می تونم بیشتر پرحرفی کنم!)

صحبتی از nil کردن متغیر آن شی نکردم، بلکه بحث من درباره آزادسازی خودکار آن شی توسط دلفی بود.
کی چنین سوالی مطرح شد؟ اتفاقا من هم صحبت از این کردم که این حرف شما ربطی به مبحث حاضر نداره. نگفتم غلطه.


آقای کشاورز، من به تسلط شما بر دلفی ایمان دارم. فکر می کنم قبول داشته باشین که راه مطرح شده "صحیحتر" و "مطمئنتر"ه. نه؟

vcldeveloper
دوشنبه 02 آبان 1384, 04:56 صبح
من هم تاکید کردم که می شه کدی نوشت که بعد از آزادسازی Application اجرا بشه.
میشه کدی را مثال بزنید که از یونیت Forms و شی Application استفاده می کنه و بعد از آزاد شدن Application همچنان به اجرا شدن خود ادامه میده؟

ضمنا چند تا مثال حقیقی از زمانهایی که FreeAndNil مشکل پیدا می کنه زده ام
من هنوز هم متوجه مواردی که شما اونها رو مشکل در FreeAndNil میدونید، نشدم!
فکر کنم باید بگیم هر دستور و تابعی در جای خودش کاربرد خودش رو داره، مواردی را که شما بعنوان اشکال مطرح کردید، من اشکال نمی دونم، البته با شما موافق هستم که در مورد سوال این آقا کد شما آسانتر و مطمئن تر هست، ولی ممکنه در شرایط دیگه ایی، اینطور نباشه (مثلا تعریف کلاس فرم در یک یونیت و تعریف متغیر فرم در داخل یک تابع، یا ایجاد یک فرم صرفا از طریق کد نویسی)

Naficy
دوشنبه 02 آبان 1384, 06:14 صبح
من هنوز هم متوجه مواردی که شما اونها رو مشکل در FreeAndNil میدونید، نشدم!
صحبت مشکل در FreeAndNil نیست. صحبت مشکلاتیه که در استفاده از اون برای حل مساله حاضر رخ می ده. مثلا این مشکل:

وقتی کاربر خودش فرم رو می بنده و شما به صورت دستی اونو Free نمی کنین، و خود فرم اینکارو انجام می ده، متغیر فرم nil نمی شه. حتی اگر از درون فرم بخواین اونو free کنین (و بنابراین از متد Release استفاده کنین) بازهم وضعیت همینه.
البته شما اشاره داشتین که:

البته با شما موافق هستم که در مورد سوال این آقا کد شما آسانتر و مطمئن تر هست،
بنابراین احتیاجی نمی بینم که در این زمینه بیشتر بحث کنم.

ولی ممکنه در شرایط دیگه ایی، اینطور نباشه (مثلا تعریف کلاس فرم در یک یونیت و تعریف متغیر فرم در داخل یک تابع، یا ایجاد یک فرم صرفا از طریق کد نویسی)
تمام صحبتهای من در مورد FreeAndNil تاکنون، همگی مقید به مسئله حاضر بوده اند. هرچند باید بگم در هر موردی، استفاده از FreeAndNil برای متغیرهای کلاس Form اگر به این دلیل صورت گیرد بخواهیم با مقایسه آن با nil بفهمیم فرم تخریب شده یا نه کاری غلط است. در هر کجا که باشد.




میشه کدی را مثال بزنید که از یونیت Forms و شی Application استفاده می کنه و بعد از آزاد شدن Application همچنان به اجرا شدن خود ادامه میده؟
چشم. در اسرع وقت.

Naficy
سه شنبه 03 آبان 1384, 03:24 صبح
شرمنده. دفعه قبل زمان اینترنت شبانه ام داشت تموم می شد، فرصت تست و ارسال نبود.
تو این 24 ساعت هزار و یک راه مختلف به ذهنم رسیده. یکی از یکی بامزه تر. اما آسونترینش اینه:


procedure MyExitProc;
begin
if not Assigned(Application) then Beep; // Beeps if application has been freed. Always occurs!
end;

begin
ExitProcessProc := @MyExitProc;
end.

این کد را به آخر یونیت فرمتان اضافه کنید.

vcldeveloper
پنج شنبه 05 آبان 1384, 04:35 صبح
تو این 24 ساعت هزار و یک راه مختلف به ذهنم رسیده. یکی از یکی بامزه تر. اما آسونترینش اینه:
شی Application در زمان اجرای برنامه ExitProcedure را تغییر میده، تغییر ExitProcedure به این شکل سبب میشه که تابع قبلی اجرا نشه (البته این چیز مهمی نیست و میشه با ذخیره آدرس قبلی، اون تابع را در تابع جدید فراخوانی کرد)، اما مسئله اینه که در یک برنامه عادی دلفی تغییر ExitProcedure در شرایط خیلی خاصی صورت میگیره، از طرف دیگه امکان دسترسی به متغیر یک فرم هم در تابع مربوطه وجود نداره.

Naficy
پنج شنبه 05 آبان 1384, 06:05 صبح
اما مسئله اینه که در یک برنامه عادی دلفی تغییر ExitProcedure در شرایط خیلی خاصی صورت میگیره، من یکی که زبونم مو در اورد:

اما در موارد واقعا نادری ممکنه کد تست بعد از آزاد شدن Application و قبل از اتمام برنامه صدا زده بشه. البته در برنامه نویسی های معمولی چنین اتفاقی نمی یفته و اگر کد تست را در جاهایی غیر از "کدهای پایانی" برنامه نوشته باشین می تونین مطمئن باشین مشکلی پیش نمی یاد.

ضمنا

من هم تاکید کردم که می شه کدی نوشت که بعد از آزادسازی Application اجرا بشه.
ضمنا چند تا مثال حقیقی از زمانهایی که FreeAndNil مشکل پیدا می کنه زده ام و اینهمه بحث روی Application بیفایده است.
گفته بودم که بحث بیفایده است. اما فقط به خاطر اصرار مجدد شما بر "نشدنی بودن این کار" و "زدن یک مثال" کد را نوشتم.


=====================================
اما در مورد پست اخیر:

شی Application در زمان اجرای برنامه ExitProcedure را تغییر میده، تغییر ExitProcedure به این شکل سبب میشه که تابع قبلی اجرا نشه
توجه دارید که من از ExitProc استفاده نکردم (که در راهنمای دلفی اشاره شده که تنها به علت backward compatibility در دلفی ارایه شده و با ساختار RTL سازگاری نداره)
من از ExitProcessProc استفاده کردم، با علم به اینکه این متغیر در هیچ جایی از دلفی ویندوز استفاده نشده. و احتیاجی به ذخیره کردن مقدار قبلی، آنهم زمانی که منظور صرفا یک مثال خلاصه است، ندیدم.

از طرف دیگه امکان دسترسی به متغیر یک فرم هم در تابع مربوطه وجود نداره.
چرا نداره؟ من تست کردم و به راحتی دسترسی داشتم!؟
اما البته در راهنمای دلفی آمده که:
ExitProcessProc specifies the last procedure to execute before the application shuts down.
و در جایی از سورس دلفی اشاره شده که این تابع زمانی صدا زده می شه که RTL کلا خوابیده. یعنی قبل از این تابع همه فرم ها تخریب شده اند. (البته مسلما هنوز می شه به "متغیر فرم" دسترسی داشت. مقدارش هم nil نخواهد بود)
اما....
اما اگر احیانا بخواین اینطور نتیجه بگیرین که راه حل FreeAndNil برای این مساله مشکلی نداره، دوباره نیاز به تاکید می شه که "مشکلات دیگری در استفاده از FreeAndNil برای چنین منظوری وجود داره که ربطی به تخریب شی Application ندارن. بنابراین روش کلا مردود است"
(البته منظور من این نبود که شما لزوما می خواین چنان نتیجه ای بگیرین...گفتم اگر کسی بخواد...)