PDA

View Full Version : سوال: بسته نشدن یک فرم



sara.mahdavi
پنج شنبه 10 مرداد 1392, 13:11 عصر
با سلام:لبخندساده:
یکی از فرم های برنامم رو وقتی با دستور Close میبندم هیچ کاری انجام نمیده

برنامه رو تریس کردم
در قسمت Vcl.Forms در تابع TCustomForm.ShowModal
فقط این دستورات تکرار میشن و هیچ موقع به پایان نمیرسه


Application.HandleMessage;
if Application.Terminated then ModalResult := mrCancel else
if ModalResult <> 0 then CloseModal;
until ModalResult <> 0;

:متفکر:مشکل از کجاست دوستان ؟؟؟؟؟؟
با تشکر:چشمک:

یوسف زالی
پنج شنبه 10 مرداد 1392, 15:33 عصر
سلام.
کاری به اون دستورات نداشته باشید.
در مورد فرم توضیحاتی بدید. این فرم MDI نیست احیانا؟
در رویداد هاش چیزی ننوشتید؟

sara.mahdavi
پنج شنبه 10 مرداد 1392, 15:50 عصر
ن MDI نیست
فکر میکنم توی کد نویسی این مشکل بوجود اومده باشه آخه اول مشکلی نداشت

چرا من توی رویداد های
OnActivate
OnClose
OnKeyPress
این فرم کدنویسی کردم

یوسف زالی
پنج شنبه 10 مرداد 1392, 16:01 عصر
خب دختر خوب منظورم اینه که کدی که احتمالا داری رو بگذاری دیگه.
در رویداد OnClose احیانا Action رو دست نزدید؟

sara.mahdavi
پنج شنبه 10 مرداد 1392, 16:09 عصر
بله :خجالت:
خب ببخشید منظورتون رو نفهمیدم دیگه:ناراحت:


procedure TFrm_Sell.FormActivate(Sender: TObject);
begin

Dm.T_Customers.Open;
dbL_FLname.ListSource.DataSet.First;
dbL_FLname.KeyValue:=dbL_FLname.ListSource.DataSet .FieldByName('ID_Customer').Value;
//-----
DM.T_SoftWare.Open;
dbL_SW_Name.ListSource.DataSet.First;
dbL_SW_Name.KeyValue:=dbL_SW_Name.ListSource.DataS et.FieldByName('ID_SoftWare').Value;

if Frm_Sell.Tag=1 then
copy_Table2Temp(L_IDSell.Caption);
dbL_FLname.ListFieldIndex:=-1;
dbL_SW_Name.ListFieldIndex:=-1;
E_SellDate.Text :=Frm_Main.slrmnthclndr1.OutDate;
end;


procedure TFrm_Sell.FormClose(Sender: TObject; var Action: TCloseAction);
begin
B_Reset.Click;
end;

Procedure TFrm_Sell.FormKeyPress(Sender: TObject; var Key: Char);
begin
if Key ='+' then begin
Frm_SoftWareList.Tag:=1;
Frm_SoftWareList.ShowModal;
end;
if Tag=2 then begin

end;
end;




procedure TFrm_Sell.B_ResetClick(Sender: TObject);
begin
E_Number.Clear;
E_Price.Clear;
E_SellDate.Clear;
E_TotalPrice.Clear;
E_Discount.Clear;
E_TotalPayment.Clear;
L_IDSell.Caption:='';
DM.CltDS_Temp.EmptyDataSet;
Tag:=0;
end;

یوسف زالی
پنج شنبه 10 مرداد 1392, 16:29 عصر
به نظر می رسه در رویداد B_Reset.Click اتفاقی می افته که مانع ادامه کار می شه.
این خط رو کامنت کنید و ادامه بدید ببینید درست می شه یا نه.
اگر درست می شه، ایراد از کد درون دکمه هست و اگر نمی شه، ایراد رو جای دیگه باید بگردید دنبالش.
تست کنید ببینید چی می شه.

sara.mahdavi
پنج شنبه 10 مرداد 1392, 16:37 عصر
اینو تست کردم هیچ مشکلی نداره
توی پست اولم گفتم بعد از اینکه از رویداد B_Reset.Click رو تموم میکنه و میخواد رویداد FormClose تموم شه در قسمت Vcl.Forms در تابع TCustomForm.ShowModal
فقط این دستوراتی که در پست اول گفتم تکرار میشن و انگار توی لوپ میوفته

نمیدونم اشکال کار کجاس:افسرده:

یوسف زالی
پنج شنبه 10 مرداد 1392, 16:43 عصر
یعنی کامنت هم کردید مشکل همچنان وجود داشت؟
پروژتون رو بگذارید بررسی کنم.

sara.mahdavi
پنج شنبه 10 مرداد 1392, 17:53 عصر
توی رویداد FormClose بعد از دستور
B_Reset.Click;
دستور Close رو نوشتم مشکل برطرف شد :متفکر:

khorsandreza
پنج شنبه 10 مرداد 1392, 19:42 عصر
یعنی کامنت هم کردید مشکل همچنان وجود داشت؟
پروژتون رو بگذارید بررسی کنم.
سلام دوست عزیز
وقت بخیر مزاحم همیشگی که همیشه ایه یاس می خونه این مشکل که خانم مهدوی نوشتند بنظر می رسه از اشکالات دلفی XE2 می باشه جالب که بدوننین من از دلفی 7 به دلفی 2010 امدم بلافاصله به دلفی XE2 رفتم دقیقا همین مشکل که در پست اول خانم مهدی نوشتند برخوردم وقتی فرم را می خواهم ببندم عملا هیچ اتفاقی نمی افته حالا من تریس نکردم که به


Application.HandleMessage;
if Application.Terminated then ModalResult := mrCancel else
if ModalResult <> 0 then CloseModal;
until ModalResult <> 0;
میره یا نه ولی موقع بستن فرم بسته نمیشه و یا خطای سریز حافظه و یا عدم تخصیص حافظه میده اول فکر می کردم اشکال از کدهای من است کلی دستکاری کردم ولی احساس می کنم با این اشکالی که خانم مهدوی نوشتند بیشتر یک خطای کامپایلر است. من هم مجبور شدم در رویداد OnClose فرم دستور Self.Close بنویسم تا فرم بسته شود
البته این اشکال در مورد فرم هائی است که بصورت ShowModal باز شده اند

نمونه خطاها را عکس گرفتم همینجا اپلود می کنم

یوسف زالی
جمعه 11 مرداد 1392, 00:36 صبح
ممکنه که در فراخوانی این رویداد برای مقدار Action چیزی ست شده باشه.
تست کنید ببینید که با این درست می شه؟
Action := caFree

khorsandreza
جمعه 11 مرداد 1392, 01:51 صبح
ممکنه که در فراخوانی این رویداد برای مقدار Action چیزی ست شده باشه.
تست کنید ببینید که با این درست می شه؟
Action := caFree
روش فرا خوانی فرمهای من به شکل زیر است من معمولا روش ذکر شده در فرم هائی که هستند fsMDIChild بکار می برم بنظرم می رسه وقتی fsNormal در این روش نیازی به آزاد کردن نباشد چون با بسته ششدن فرم عملا فرم از بین می ره

try
PersInfoForm := TPersInfoForm.Create(Application);
PersInfoForm.ShowModal;
Finally
PersInfoForm.Destroy;
End;

SAASTN
جمعه 11 مرداد 1392, 04:58 صبح
بنظرم می رسه وقتی fsNormal در این روش نیازی به آزاد کردن نباشد چون با بسته ششدن فرم عملا فرم از بین می ره
اینطور نیست، شما مسئول آزادسازی تمامی فرم هایی هستید که خودتون با کد ایحاد کردید. بسته شدن فرم تنها به معنی مخفی شدن فرم هست نه آزاد کردن اون. در صورتی که این فرمها رو آزاد نکنید اونها تا زمان پایان اجرای برنامه تو حافظه می مونن و برنامه دچار نشط حافظه می شه.
اما تفاوت در عملکرد فرم موقع بسته شدن تو حالتهای fsMDIChild و fsNormal به تفاوت در تعریف این دو حالت بر می گرده. همونطور که گفتم بسته شدن فرم تنها به معنی مخفی شدن موقتی فرم هست. بیشتر فرمهای برنامه فرمهایی هستن که در طول اجرای برنامه ممکنه چندین بار بهشون احتیاج داشته باشیم. مثلا کاربر ممکنه چند بار فرم مربوط به یه گزارش رو باز کنه. این همون حالت پیشفرض فرمهای دلفی هست. فرمهای Auto-Create که پراپرتی FormStyle اونها برابر fsNormal هست. یه نمونه از تمام این فرمها در زمان اجرای برنامه ساخته میشه و تو یه متغیر سراسری به نام اون فرم قرار می گیره. این متغیر در قسمت interface یونیت مربوط به همون فرم تعریف شده:
var
Form1: TForm1;

پس زمانی که یه فرم رو Show می کنیم، در واقع اون فرم بطور مخفی تو حافظه وجود داره و فقط نمایش پیدا می کنه و وقتی اون رو Close می کنیم دوباره مخفی میشه. اما آزاد شدن این فرم ها هم بطور خودکار در زمان پایان اجرای برنامه انجام میشه. پس اگه ما یک فرم رو خودمون ایجاد کنیم و تنها اون رو Close کنیم این فرم تا انتهای اجرای برنامه بطور مخفی تو حافظه می مونه. در واقع ایجاد و آزادسازی فرمها یا باید توسط خود دلفی انجام بشه یا برنامه نویس. بودن فرم تو لیست فرمهای Auto-Create پروژه به این معنی هست که ما می خوایم خود دلفی ایجاد و آزادسازی این فرم رو مدیریت کنه. اما اگه خودمون بخوایم به هر دلیلی فرم رو با کد ایجاد کنیم باید اون رو از لیست Auto-Create خارج کنیم. وگرنه خود دلفی هم در زمان اجرای برنامه یه نمونه از این فرم میسازه که عملا هیچ وقت ازش استفاده نمی کنیم.

اما تعریف فرمهای MDIChild چیز دیگه ای هست. از نظر تعریف هر کدوم از این فرمها حاوی یه سند در یه برنامه MultiProject هستند. یعنی برنامه ای که لازم داره بطور همزمان محتویات چند فایل مختلف رو به صورت گرافیکی نمایش بده. باز کردن فایل در این برنامه ها به این معنی هست که کاربر در حال حاظر می خواد محتویات فایل رو ببینه یا تغییر بده. درستش اینه که این فرمها از لیست Auto-Create خارج بشن و توسط برنامه نویس ایجاد بشن. از اونجایی که بستن فرم تنها به معنی مخفی کردن موقتی فرم بود این فرمها موقع بسته شدن فقط داخل خود فرم اصلی Minimize می شن، اگر دیگه به این فرم نیازی نداشته باشیم باید اون رو آزاد کنیم. تمام این تعاریف رو میشه از متد Close کلاس TCustomForm استنباط کرد:
procedure TCustomForm.Close;
var
CloseAction: TCloseAction;
begin
if fsModal in FFormState then
ModalResult := mrCancel
else
if CloseQuery then
begin
if FormStyle = fsMDIChild then
if biMinimize in BorderIcons then
CloseAction := caMinimize else
CloseAction := caNone
else
CloseAction := caHide;
DoClose(CloseAction);
if CloseAction <> caNone then
if Application.MainForm = Self then Application.Terminate
else if CloseAction = caHide then Hide
else if CloseAction = caMinimize then WindowState := wsMinimized
else Release;
end;
end;

همونطور که می بینید نوشته شده اگر فرم fsMDIChild نیست Hide بشه و در غیر اینصورت Minimize بشه. جالب اینجاس که اگه برنامه نویس امکان Minimze شدن رو هم از فرم گرفته باشه در عمل با فراخونی Close هیچ اتفاقی نمی افته و فرم بدون کوچکترین حرکتی عین کرفس تو چشم کاربر نگاه می کنه!
از اونجایی که مایکروسافت استفاده از سیستم MDI رو شرعا حرام اعلام کرده این روزا کمتر برنامه ای از این فرمها استفاده می کنه. اگه یادتون باشه تو ورژن های قدیمی تر MSWorld هم وقتی چند فایل رو باز می کردیم می تونستیم فایل ها رو هم زمان تو محیط ورد ببینیم، اما الان دیگه هیچ برنامه ای این کار رو نمی کنه، الان برنامه ها یا از منطق TabBar استفاده می کنن یا مثل ورژن های جدید همین ورد هر فایل رو تو یه برنامه جداگونه باز می کنن. اما با تمام این بی مهری هایی که کمپانی های فرنگی نسبت به این مدل کارآمد رابط گرافیکی می کنن، برنامه نویسای ایرانی همچنان یادش رو زنده نگه داشتن!(منجمله خودم:اشتباه:)

این مشکل که خانم مهدوی نوشتند بنظر می رسه از اشکالات دلفی XE2 می باشه جالب که بدوننین من از دلفی 7 به دلفی 2010 امدم بلافاصله به دلفی XE2 رفتم دقیقا همین مشکل که در پست اول خانم مهدی نوشتند برخوردم وقتی فرم را می خواهم ببندم عملا هیچ اتفاقی نمی افته
هرچند نمیشه قسم خورد ولی خیلی بعیده که این مشکل به دلفی مربوط باشه، چون پیاده سازی این بخشها به عهد بوق برمی گرده. اگه همچین باگی هم تولید شده باشه چیزی نیست که بخواد زیاد مخفی بمونه.
به احتمال زیاد علت از سمت خود برنامست. در مورد MDIChild که توضیح دادم، اما در مورد فرمهای Normal همونطور You-See گفت ممکنه یه جایی توی OnClose مقدار پارامتر Action به caNone تغییر کرده باشه.
احتمال دیگه که هم در مورد شما هم در مورد sara.mahdavi ممکنه اتفاق افتاده باشه اینه که یه جایی ModalResult به mrNone یا صفر ست بشه. دوباره برگردیم به TCustomForm.Close، تو خط اول می بینیم که نوشته اگه فرم تو حالت Modal بود فقط ModalResult رو mrCancel کن. این کار باعث میشه که همون حلقه ای که تو ShowModal دیدین متوقف بشه. وقتی فرم رو ShowModal می کنیم قطعه کدی که ShowModal رو صدا کرده روی همون خط متوقف می مونه تا فرم Modal بسته بشه. اینکار با ست کردن ModalResult به مقداری غیر از mrNone توی هر جایی از برنامه انجام می شه. با Close کردن فرم Modal هم داریم همین کار رو می کنیم، اما اگه یه جایی توی OnClose یا OnCloseQuery دوباره ModalResult رو mrNone کنیم باز فرم باز می مونه.
نکته دیگه این که بستن یه فرم Modal با صدا کردن Close کار درستی نیست. همونطور که گفتم و از متد ShowModal هم معلومه، فرم Modal رو باید با ست کردن ModalResult فرم ببندیم. یعنی اگه تو یه شرایطی فهمیدیم که کار با فرم تموم شده باید ModalResult رو مثلا mrOK یا mrCancel کنیم. اگه این شرایط فشرده شدن دکمه تائید باشه حتی نیاز به کد نویسی هم نیست، کافیه پراپرتی ModalResult دکمه رو ست کنیم. در واقع هرجا دیدید لازمه خودتون مستقیما با کد ModaResult فرم رو ست کنید بدونید با احتمال زیادی اصول ساخت یافتگی تو کدتون رعایت نشده و تن دایجسترا داره تو گور میلرزه!

sara.mahdavi
جمعه 11 مرداد 1392, 05:58 صبح
ببینید وقتی که توی رویداد Close فرم یک دستور مثلا همین B_Reset.Click رو مینویسم فرمم بسته نمیشه البته من بیشتر فرم هام رو ShowModal باز میکنم
این دستور Action := caFree رو هم چک کردم که فایده ای نداشت .

حالا بعد از تمامی کدهایی که توی رویداد Close فرم نوشتم ، دستور Close رو مینویسم فرمم بسته میشه
ولی در بعضی مواقع درست کار نمیکنه که بجای دستور Close از دستور ModalResult :=1 که دوست خوبمون SAASTN (http://barnamenevis.org/member.php?21955-SAASTN) فرمودند استفاده کردم و جواب داد

با تشکر

khorsandreza
جمعه 11 مرداد 1392, 14:34 عصر
سلام


به احتمال زیاد علت از سمت خود برنامست. در مورد MDIChild که توضیح دادم، اما در مورد فرمهای Normal همونطور You-See گفت ممکنه یه جایی توی OnClose مقدار پارامتر Action به caNone تغییر کرده باشه.

مگه ما در هر فرم چند تا رویداد OnClose داریم وقتی در این رویداد هیچ کدی نوشته نشده چگونه بگیم که به پارامتر Action مقدار پاس شده
اول یک سوال مگه این دستور PersInfoForm.Destroy; فرم را از حافظه آزاد نمی کنه؟
و مطلب دوم شما یک تست کوچک بکنید فرمی را از داخل فرم دیگه چندین بار فراخوانی کنید و تریس انجام بدین دقیقا می ره پست اولی که خانم مهدوی نوشتند میشه می افته تو حلقه بی نهایت (بنظر من البته شاید اشتباه می کنم) هر چند برنامه فریز نمیشه ولی فرم نیز بسته نمیشه
من یک احنمال دیگه هم میدم شاید به نسخه هائی متفاوتی از دلفی باشه مثلا نسخه من با نسخه خانم مهدوی یکی باشه و این اشکال تلاقی بکنه هر چند همین کار را یکی از دوستان گفتم انجام داده می گه اشکالی ندیدم

SAASTN
جمعه 11 مرداد 1392, 15:50 عصر
ولی در بعضی مواقع درست کار نمیکنه که بجای دستور Close از دستور ModalResult :=1 که دوست خوبمون SAASTN فرمودند استفاده کردم و جواب داد
صدا کردن Close هیچ تفاوتی با ست کردن ModalResult نداره. اگه مشکلی وجود داشته باشه هنوز حل نشده. اینکه شما توقع دارید فرم بسته بشه اما بدون صدا کردن دوباره Close این اتفاق نمی افته یعنی روند منطقی برنامه به درستی اجرا نمیشه. علت اون رو میشه در متد Click کلاس TCustomButton پیدا کرد:
procedure TCustomButton.Click;
var
Form: TCustomForm;
begin
Form := GetParentForm(Self);
if Form <> nil then Form.ModalResult := ModalResult;
inherited Click;
end;

اینجا نوشته شده ModalResult فرم پدر دکمه به مقدار ModalResult دکمه تغییر کنه. یعنی زمانی که توی OnClose شما متد Click یه دکمه رو صدا می کنید اگه ModalResult اون دکمه رو ست نکرده باشید عملا دارید خودتون جلوی بسته شدن فرم رو می گیرید. تست اون هم سادس، توی OnClose یه BreakPoint رو Button1.Click; بذارید و مقدار ModalResult فرم رو قبل و بعد از اجرای اون ببینید، قبل از اجرای Click این مقدار 2 یا همون mrCancel هست اما بعد از اجرای Click این مقدار به 0 یا mrNone تغییر می کنه و باعث می شه فرم بسته نشه. شما دو راه دارید، اول این که ModalResult دکمه رو ست کنید، دوم این که بجای این که متد Click رو صدا کنید مستقیما رویداد OnClick دکمه رو صدا کنید:
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Button1Click(Sender);
end;


مگه ما در هر فرم چند تا رویداد OnClose داریم وقتی در این رویداد هیچ کدی نوشته نشده چگونه بگیم که به پارامتر Action مقدار پاس شده
یه OnClose داریم، غیر از Action باید ModalResult هم بررسی بشه. البته امیدوارم اون قضیه مربوط به MDIChild حل شده باشه، چون هیچ ربطی به مشکل sara.mahdavi نداره.

مگه این دستور PersInfoForm.Destroy; فرم را از حافظه آزاد نمی کنه؟
چرا، آزاد می کنه. من اون مطلب دور و دراز رو در جواب به پست قبلیتون نوشتم:

بنظرم می رسه وقتی fsNormal در این روش نیازی به آزاد کردن نباشد چون با بسته ششدن فرم عملا فرم از بین می ره




و مطلب دوم شما یک تست کوچک بکنید فرمی را از داخل فرم دیگه چندین بار فراخوانی کنید و تریس انجام بدین دقیقا می ره پست اولی که خانم مهدوی نوشتند میشه می افته تو حلقه بی نهایت (بنظر من البته شاید اشتباه می کنم) هر چند برنامه فریز نمیشه ولی فرم نیز بسته نمیشه
این رفتار طبیعی فرم در حالت Modal هست. قبلا هم گفتم، وقتی شما یه فرم رو ShowModal میکنید روند اجرای کد فراخونی کننده متوقف میشه، البته این به معنی فریز شدن برنامه یا گیر کردن برنامه تو حلقه بی نهایت نیست. اون حلقه فقط برای این نوشته شده تا فرم از بسته شدن خودش مطلع بشه و اجرای برنامه به دستورات بعد از فراخونی ShowModal برگرده.
برای تست این عملکرد یه برنامه ساده بنویسید شامل دو فرم، توی فرم دوم دوتا دکمه قرار بدین و ModalResult یکیشون رو mrOK و اون یکی رو mrCancel کنید. توی فرم اصلی یه دکمه قرار بدید و توی OnClickش بنویسید:
procedure TForm1.Button1Click(Sender: TObject);
var
Form2ModalResult: Integer;
begin
Form2ModalResult := Form2.ShowModal;
if Form2ModalResult = mrOk then
ShowMessage('User clicked OK button')
else
ShowMessage('User clicked Cancel button');
end;

با اجرای این کد دو چیز متوجه می شیم، اول اینکه تا قبل از بسته شدن Form2 هیچ مسجی نمایش پیدا نمی کنه، یعنی انگار برنامه روی خط Form2ModalResult := Form2.ShowModal; متوقف شده. دوم این که ما از داخل Form1 می تونیم بفهمیم که کاربر توی Form2 چه تصمیمی گرفته. سیستم Modal برای ایجاد Dialog ها یا پنجره های محاوره ای پیاده سازی شده. یعنی زمانی که ما از کاربر می خوایم چیزی رو تعیین کنه یا به سوالی جواب بده و بعد ما بر اساس تصمیم کاربر کارهای متفاوتی انجام بدیم.

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

khorsandreza
شنبه 12 مرداد 1392, 22:29 عصر
سلام دوستان
مشکلی که موقع یسته شدن فرم پیش می آید بشکل زیر است واقعا این خطا اذیت می کنه تصویر را ببینید
ضمننا این هم کدی است که برروی کلید Close نوشته شده

DM.MyDB.Close;
Self.Close;


http://etaksan.ir/images/8888.png

SAASTN
یک شنبه 13 مرداد 1392, 01:07 صبح
مشکلی که موقع یسته شدن فرم پیش می آید بشکل زیر است واقعا این خطا اذیت می کنه تصویر را ببینید
این مطلب خارج از موضوع این تاپیک هست. باید یه تاپیک جدید برای طرحش ایجاد کنید. ضمنا با این روش طرح مسئله هیچ کس نمی تونه کمکی به شما بکنه. اون خطای AV هزاران علت می تونه داشته باشه که کسی نمی تونه حدس بزنه. شما باید کدتون رو دیباگ کنید تا دقیقا محلی که دسترسی غیر مجاز حافظه ای رخ میده رو پیدا کنید. چیزی که میشه گفت اینه که DM یا MyDB یا Self قبلا آزاد شدن. یا خطا در OnClose فرم رخ می ده یا ...