ورود

View Full Version : سوال: این خطا یعنی چی؟



vb.net2008
دوشنبه 03 مرداد 1390, 13:16 عصر
سلام
این خطا چه معنی داره؟
72900

یوسف زالی
دوشنبه 03 مرداد 1390, 15:11 عصر
سلام.
این خطا یعنی دسترسی غیر مجاز به منطقه ای از حافظه.
بیشتر مواقعی پیش میاد که خصوصیات شی که Create نشده را ست کنید.
رو چه خطی ارور دارید؟
کدش رو یگذارید.

vb.net2008
دوشنبه 03 مرداد 1390, 19:48 عصر
ممنون مشکلش حل شد. فقط یه سوال. برای یه کلاس حتما باید یه سازنده بنویسیم؟
چون من تو برنامم. واسه کلاسم اولش یه سازنده ننوشته بودم. اولش وقتی که یه تبع از کلاس رو فراخوانی می کردم مشکلی نداشت. اما بعدش که پشت سرش یه تابع دیگه از تابع رو فراخوانی می کردم. همین خطا رو میداد.
بعدش که رفتم یه سارنده واسه تابعم درست کردم دیگه خطا نداد.
(شاید سوالی که پرسیدم خیلی مسخره باشه. )

یوسف زالی
دوشنبه 03 مرداد 1390, 20:31 عصر
نه. اجبار نیست در هر کلاسی سازنده داشته باشید.
حتی همه شی ها هم مجبور به فراخوانی سازنده نیستند.
مثلا کلاس TList نیازی به سازنده نداره.
در حالت عمومی سازنده ها وقتی "لازم" می شن که نیاز به مقداردهی اولیه خصوصیت ها یا متغیر ها، تعیین مشخصات اولیه مثل طول آرایه، ست کردن اشاره گر ها و کلا مقداردهی های پیش فرض داریم.
اگر از کلاسی مشتق گرفتید که خودش سازنده رو اجباری داره برای ساختن شی از کلاستون مجبورید سازنده رو فرا بخونید.
علت اینکه گاهی از بعضی خصلت های کلاسها بدون فراخواندن سازندشون می تونیم استفاده کنیم، اینه که در اون قسمت نیازی به هیچ مقدار دهی اولیه نبوده.
برای مثال یک دکمه بدون نیاز به ساخته شدن می تونه از Tag به عنوان نماینده خصوصیات و Focused به عنوان مثالی از توابع استفاده کنه.
اما این رو هم باید بپذیرید که اگر بدون فراخوانی متد سازنده از کلاسی استفاده می کنید ممکنه وارد حافظه مربوط به جاهای دیگه برنامتون بشید که حتی کجاش رو هم ندونید.
مثالش برای من اتفاق افتاد:
یک دکمه رو بدون ساخته شدن در زمان اجرا Caption اون رو عوض کردم، Caption یکی از دکمه های فرمم عوض میشد!
توصیه:
حتی اگر نیازی به هیچ سازنده ای برای کلاستون حس نمی کنید برای مصارف آتی برای اون سازنده در نظر بگیرید.

soft-c
دوشنبه 03 مرداد 1390, 20:37 عصر
یک سوای دارم
چرا وقتی یک کامپوننت مثلا button را روی فرم قرار می دهیم و دلفی خودکار یک شی از آن می سازد ، ولی سازنده را صدا نمی زند ولی با این حال می تونبم با اون شی کار کنیم
تشکر

یوسف زالی
دوشنبه 03 مرداد 1390, 21:19 عصر
اصلا چرا اونو میگی؟
مگه خود فرم رو ما میسازیم؟
اما به OnCreate فرم که نگاه کنی و توش کد بگذاری می بینی که صدا زده میشه و این نشون می ده که کامپایلر داره اون شی رو می سازه.
این جور چیزا کامپوننت هستند و خصوصیات Published خودشون رو در Object Inspector در اختیار قرار می دن و از همه مهمتر اینکه "توسط کامپایلر ساخته می شن"
شما هم می تونی از کلاست یک کامپوننت بسازی و پس از نصب اون بدون اینکه مستقیم بسازی یا حتی مقادیرش رو بدی، از طریق Object Inspector و در زمان طراحی با اون کار کنی.

کلا برای ساخت یک شی در دلفی باید خصوصیاتی از اون که در Published قرار دارند هم ساخته شن.
نمونه اون فرم هست.
شما می تونی در Private یک دکمه بگذاری ولی اون ساخته نمی شه.
اما اگر در Published بگذاری باید ساخته بشه و علت اینکه دلفی هم بهش گیر میده همینه.
اگر قراره ساخته بشه کجا قرار داره؟ اندازش چقدره، نمی تونه در Object Inspector هم نمایشش بده.

vb.net2008
سه شنبه 04 مرداد 1390, 13:02 عصر
سلام
ببخشید باز یه مشکل دیگه.
72939
من تو کلاسم از TCustomControl ارث بری می کنم. چون توی کلاسم اشیا داخل فرم رو می سازم. من ویندوز 7 دارم و نمی تونم از help استفاده کنم. یه لیستی از خطاهای delphi رو ندارین؟

vcldeveloper
سه شنبه 04 مرداد 1390, 13:03 عصر
فقط یه سوال. برای یه کلاس حتما باید یه سازنده بنویسیم؟
یک کلاس همیشه یک سازنده (constructor) داره؛ اگر شما هم اون رو ننویسید، از سازنده کلاس پایه اش (TObject) استفاده خواهد شد. پس وجود یک سازنده الزامی هست.


نه. اجبار نیست در هر کلاسی سازنده داشته باشید.
حتی همه شی ها هم مجبور به فراخوانی سازنده نیستند.
مثلا کلاس TList نیازی به سازنده نداره.
در حالت عمومی سازنده ها وقتی "لازم" می شن که نیاز به مقداردهی اولیه خصوصیت ها یا متغیر ها، تعیین مشخصات اولیه مثل طول آرایه، ست کردن اشاره گر ها و کلا مقداردهی های پیش فرض داریم.
اگر از کلاسی مشتق گرفتید که خودش سازنده رو اجباری داره برای ساختن شی از کلاستون مجبورید سازنده رو فرا بخونید.
اشتباه هست؛ همه کلاس ها باید سازنده داشته باشند، و سازنده هم دارند. تا زمانی که سازنده یک کلاس فراخوانی نشه، حافظه ایی به اون کلاس بر روی Heap اختصاص داده نمیشه. یک سازنده علاوه بر این که کد شما برای مقداردهی اولیه به خصوصیات و فیلدهای کلاس تان را انجام میده، متد NewInstance را فراخوانی میکنه تا هم حافظه مورد نیاز شی مورد نظر به آن اختصاص پیدا کنه، و هم با فراخوانی InitInstance فضای حافظه اختصاص داده شده به شی مورد نظر مقداردهی اولیه بشه.


علت اینکه گاهی از بعضی خصلت های کلاسها بدون فراخواندن سازندشون می تونیم استفاده کنیم، اینه که در اون قسمت نیازی به هیچ مقدار دهی اولیه نبوده.
اشتباه هست؛ هیچ فیلدی از یک شی بدون این که سازنده کلاس مربوط به اون شی فراخوانی بشه، قابل دسترس نیست، مگر اینکه اون فیلد به صورت class var تعریف شده باشه. اگر بر فرض کسی کدی نوشت که تونست بدون ساخت یک شی، به خصوصیات اون شی دسترسی پیدا کنه، این اسمش فقط شانس هست! چون شی ایی که ساخته نشده باشه، اگر nil باشه که دسترسی به خصوصیاتش موجب Access Violation میشه. اگر هم nil نباشه، یعنی قبلا یک بار ساخته شده بود، ولی بعدش Free شده؛ اون وقت حافظه ایی که این شی بهش اشاره میکنه نامعتبر هست. اگر در زمان دسترسی مجددا به اون شی، مدیر حافظه چیزی در اون بخش از حافظه ننوشته باشه، یا اون بخش از حافظه را به سیستم عامل واگذار نکرده باشه، ممکنه برنامه نویس مربوطه با خوش شانسی، به لاشه باقی مانده از اون شی در حافظه دسترسی پیدا کنه. اگر اون بخش از حافظه به شی دیگه ایی واگذار شده باشه، ممکنه مقدار اشتباهی که مربوط به شی دیگه ایی هست را دریافت کنه، یا اینکه Access Violation بگیره. اگر هم که اون حافظه به سیستم عامل برگشت داده شده باشه، باز Access Violation میگیره. پس تصور اینکه اگر یک شی داشته باشیم که Create نشده، ولی میشه به داده هاش دسترسی داشت، یک تصور کاملا غلط هست. شما فقط می تونید به class var به عنوان داده ایی از کلاس (نه از شی) بدون فراخوانی سازنده یک کلاس دسترسی داشته باشید.




چرا وقتی یک کامپوننت مثلا button را روی فرم قرار می دهیم و دلفی خودکار یک شی از آن می سازد ، ولی سازنده را صدا نمی زند ولی با این حال می تونبم با اون شی کار کنیم
دلفی برای تک تک کامپوننت هایی که روی فرم قرار میدید، در هنگام لود کردن فرم از DFM، سازنده هایشان را فراخوانی میکنه.



مگه خود فرم رو ما میسازیم؟
اما به OnCreate فرم که نگاه کنی و توش کد بگذاری می بینی که صدا زده میشه و این نشون می ده که کامپایلر داره اون شی رو می سازه.
کد ساختنش در فایل DPR پروژه تون هست. در فایل DPR پروژه خط مربوط به ساخته شدن فرم مورد نظرتان (Application.CreateForm ....) را حذف کنید، اون وقت ببینید که آیا می تونید به اون فرم یا داده هایش دسترسی داشته باشید یا نه؟!



کلا برای ساخت یک شی در دلفی باید خصوصیاتی از اون که در Published قرار دارند هم ساخته شن.
نمونه اون فرم هست.
شما می تونی در Private یک دکمه بگذاری ولی اون ساخته نمی شه.
اما اگر در Published بگذاری باید ساخته بشه و علت اینکه دلفی هم بهش گیر میده همینه.
این هم اشتباه هست؛ علت اینکه اگر یک دکمه به صورت private تعریف بشه، دلفی نمیتونه اون رو خودش Create کنه این هست که برای ساخت یک کامپوننت، شما یا باید خودتان آن را دستی بسازید، یا اینکه باید دلفی این کار را به طور خودکار انجام بده. برای اینکه دلفی بتونه یک کامپوننت را به طور خودکار بسازه، باید درباره نوع اون کامپوننت اطلاعات کافی در زمان اجرای برنامه داشته باشه. به این اطلاعات میگن RTTI. وقتی یک خصوصیت در بخش published یک کلاس تعریف میشه، این کار به کامپایلر میگه که این خصوصیت نیاز به تولید RTTI داره، در نتیجه کامپایلر در هنگام کامپایل کد، یک سری دادهاضافی برای آن خصوصیت خاص تولید میکنه که در زمان اجرای برنامه بشه اطلاعات مربوط به نوع داده اون خصوصیت را استخراج کرد. وقتی فرمی لود میشه، دلفی بر اساس اینکه چه خصوصیاتی RTTI دارند، با استفاده از اون داده های اضافی، اشیاء مورد نظر را به طور خودکار میسازه.
اگر برنامه نویسی بخواد خودش این کارها را در کد انجام بده، میتونه به راحتی کامپوننت های مورد نظرش را به صورت private تعریف کنه، و در متد Create فرم مورد نظر، خودش از طریق کد، تک تک اون کامپوننت ها را بسازه و به خصوصیاتشان مقدار بده، اما با این کار، پشتیبانی طراح گرافیکی فرم در IDE دلفی را از دست میده، و باید برای هر تغییری که در خصوصیات اون کامپوننت ها میخواد اعمال کنه، کد بنویسه.

یوسف زالی
سه شنبه 04 مرداد 1390, 14:23 عصر
ممنون از اینکه اشتباهاتم رو گفتید.
اما


نه. اجبار نیست در هر کلاسی سازنده داشته باشید

اینجا منظورم دوباره پیاده کردن Constructor بود. نه اینکه کلا کلاسی وجود داشته باشه که سازنده نداره. اینم می دونم که هر کلاسی بالاخره به TObject ختم میشه که اونم سازنده داره.
در مورد دوم هم میپذیرم که بیانم بد بوده و علمم ناکافی.
اما دیده بودم توابعی از کلاسها رو که بدون نیاز به ساخته شدن کلاس میشه فراخوانی شون کرد. مثل استاتیک در سی شارپ.
مورد سوم هم همینطوره.
منظور من بیان ساده این اتفاقات بود که ظاهرا گند زدم!!
در مورد RTTI هم می دونم. و اینکه چه اتفاقی در موقع ران شدن می افته...

ممنون از بابت توضیحات جامعتون.
:اشتباه:

vb.net2008
سه شنبه 04 مرداد 1390, 18:09 عصر
یکی جوابمو بده.
من یه frmmain دارم که می خوام یکسری از کنترل هاشو در زمان اجرا بسازم.ساخت این کنترل ها رو داخل یه کلاس به نام Raak_Cpage انجام می دم
قسمت public فرم frmmain اینطوری نوشتم.

public
Panel,Panel4,Panel5,Panel6:TPanel;
Memo:TMemo;
Image,Image3:array of TImage;
DBGridCtrl1:TDBCtrlGrid;
procedure ImgClick(Sender:TObject);
procedure Img3Click(Sender:TObject);


توکلاسم اشیا رو اینطوری ساختم

frmMain.Panel:=TPanel.Create(nil);
frmMain.Panel.Parent:=frmMain;
frmMain.Panel.Left:=180;
frmMain.Panel.Top:=240;
frmMain.Panel.Width:=650;
frmMain.Panel.Height:=430;
frmMain.Panel.BevelOuter:=bvNone;
frmMain.Panel.Color:=clWhite;
frmMain.Memo:=TMemo.Create(self);
frmMain.Memo.Parent :=frmMain.Panel;
frmMain.Memo.Left:=0;
frmMain.Memo.Top :=0;
frmMain.Memo.Text:=DM.Q1['PageText'];
frmMain.Memo.Alignment:=taRightJustify;
frmMain.Memo.ScrollBars:=ssVertical;
frmMain.Memo.Width:=650;
frmMain.Memo.Height:=430;
frmMain.Memo .Visible :=true;


البته این فقط یه قطعه کد.
حالا یک مشکلی که هست اینکه اگه بخوام این اشیایی رو که در زمان اجرا داخل کلاس روی frmmain ساخته می شن رو در داخل یونیت مربوط به frmmain مثلا از بین ببرم یا هر دستگاری روشون انجام بدم خطای
72948
میده.

vcldeveloper
سه شنبه 04 مرداد 1390, 19:01 عصر
اما دیده بودم توابعی از کلاسها رو که بدون نیاز به ساخته شدن کلاس میشه فراخوانی شون کرد.
اون ها class function هستند، که به جای اینکه به یک نمونه (instance) از کلاس وابسته باشند، به خودِ کلاس وابسته هستند؛ و کارکردشون تقریبا مشابه static method ها در #C یا جاوا هست.


یکی جوابمو بده.
من یه frmmain دارم که می خوام یکسری از کنترل هاشو در زمان اجرا بسازم.ساخت این کنترل ها رو داخل یه کلاس به نام Raak_Cpage انجام می دم
کد اون کلاس Raak_Cpage رو اینجا بذارید.
اگر اون کنترل ها متعلق به کلاس TfrmMain هستند، دیگه چرا اونها رو در Raak_CPage میسازدید؟ در همون فرم اینها رو بسازید.
اون کد دومی که برای ساخت کنترل ها قرار دادید، مربوط به چه کلاسی هست؟ اگر مربوط به Raak_CPage هست، چرا پارامتر Owner مربوط به متد TMemo.Create را Self دادید؟ Self در اونجا به همون Raak_CPage اشاره میکنه، نه به frmMain. در ضمن، مشخص نکردید که نمونه شی مربوط به Raak_CPage کی ساخته میشه و کی آزاد میشه.

اون پیام خطا علتش مشخص هست، شما دارید به یک شی ایی دسترسی پیدا می کنید که قبل از دسترسی شما آزاد شده، ولی مقدار اشاره گرش nil نشده، به همین جهت به یک آدرس نامعتبر 00000050 اشاره میکنه.

vb.net2008
سه شنبه 04 مرداد 1390, 19:18 عصر
unit Raak_CPage;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs,ExtCtrls,StdCtrls, DBCtrls, dbcgrids,ShockwaveFlashObjects_TLB,ADODB
,DBGrids,DB,axCtrls,jpeg ;
type
Raak_Page=class(TCustomControl)
procedure ShowPage(PageID:Integer);
constructor create;
end;

implementation
uses DM_Unit,Unit1, Math;
constructor Raak_Page.create;
begin
end;
procedure Raak_Page.ShowPage(PageID:Integer);
var Param:integer;
dir:string;
ADOContainer: TCustomADODataSet;
Graphic:TGraphic;
BlobStream: TStream;
JPEGImage: TJPegImage;
Ext: string;
i:Byte;
c,b:integer;
DS: TCustomADODataSet;
sr : TSearchRec;
result:Int64;
begin
frmMain.PageID:= DM.Q2['PageID'];
if frmMain.Vis=1 then
begin
frmMain.Panel.Destroy;
frmMain.Vis:=0;
end;
frmMain.Label7.Visible:=true;
frmMain.Label7.Caption:= DM.Q2['MenuCaption'];
DM.Q1.Close ;
DM.Q1.SQL.Clear ;
DM.Q1.SQL.Add('Select * from tbl_page where ID=:ID') ;
DM.Q1.Parameters.ParamByName('ID').Value:=PageID ;
DM.Q1.Open ;
if DM.Q1.RecordCount>0 then
begin
if DM.Q1['PageType']=0 then
begin
frmMain.Panel:=TPanel.Create(frmMain);
frmMain.Panel.Parent:=frmMain;
frmMain.Panel.Left:=180;
frmMain.Panel.Top:=240;
frmMain.Panel.Width:=650;
frmMain.Panel.Height:=430;
frmMain.Panel.BevelOuter:=bvNone;
frmMain.Panel.Color:=clWhite;
frmMain.Memo:=TMemo.Create(frmMain);
frmMain.Memo.Parent :=frmMain.Panel;
frmMain.Memo.Left:=0;
frmMain.Memo.Top :=0;
frmMain.Memo.Text:=DM.Q1['PageText'];
frmMain.Memo.Alignment:=taRightJustify;
frmMain.Memo.ScrollBars:=ssVertical;
frmMain.Memo.Width:=650;
frmMain.Memo.Height:=430;
frmMain.Memo .Visible :=true;
frmMain.Memo.BorderStyle:=bsNone;
frmMain.Memo.Color:=clInactiveBorder;
frmMain.Vis:=1
end
else if DM.Q1['PageType']=1 then
begin
//if frmMain.Vis=1 then
//frmMain.Panel.Destroy;
//frmMain.PageID:= DM.Q2['PageID'];
Param:=DM.Q1['PageParam'];
//frmMain.PageID.Text:=inttostr(Param);
DM.Q1.Close ;
DM.Q1.SQL.Clear ;
DM.Q1.SQL.Add('Select * from tbl_job where CategoryID=:ID') ;
DM.Q1.Parameters.ParamByName('ID').Value:=Param;
DM.Q1.Open ;
frmMain.Panel:=TPanel.Create(frmMain);
frmMain.Panel.Parent:=frmMain;
frmMain.Panel.Left:=180;
frmMain.Panel.Top:=240;
frmMain.Panel.Width:=650;
frmMain.Panel.Height:=430;
frmMain.Panel.BevelOuter:=bvNone;
frmMain.Panel.Color:=clWhite;
frmMain.Group2:=TGroupBox.Create(frmMain);
frmMain.Group2.Parent:=frmMain.Panel;
frmMain.Group2.Left:=1;
frmMain.Group2.Top:=10;
frmMain.Group2.Width:=645;
frmMain.Group2.Height:=59;
frmMain.Group2.Color:=$008DF9FC;
frmMain.Lab6:=TLabel.Create(frmMain);
frmMain.Lab6.Parent:=frmMain.Group2;
frmMain.Lab6.Left:=469;
frmMain.Lab6.Top:=27;
frmMain.Lab6.Caption:='ÚÈÇÑÊ ãæÑÏ äÙÑ';
frmMain.Edit:=TEdit.Create(frmMain);
frmMain.Edit.Parent:= frmMain.Group2;
frmMain.Edit.Left:=202;
frmMain.Edit.Top:=23;
frmMain.Edit.Width:=257;
frmMain.Edit.Height:=19;
frmMain.Edit.BiDiMode:=bdRightToLeft;

frmMain.btn:=TButton.Create(frmMain);
frmMain.btn.Parent:=frmMain.Group2;
frmMain.btn.Caption:='ÌÓÊÌæ';
frmMain.btn.Left:=112;
frmMain.btn.Top:=21;
frmMain.btn.OnClick:=frmMain.btnclick;
frmMain.DBGridCtrl1:=TDBCtrlGrid.Create(frmMain);
frmMain.DBGridCtrl1.Parent:=frmMain.Panel;
frmMain.DBGridCtrl1.Left:=1;
frmMain.DBGridCtrl1.Top:=80;
frmMain.DBGridCtrl1.Width:=645;
frmMain.DBGridCtrl1.DataSource:=DM.Q1DS ;
frmMain.DBGridCtrl1.PanelHeight:=72;
//frmMain.DBGridCtrl1.PanelBorder:=gbNone;
frmMain.DBGridCtrl1.RowCount:=4;
frmMain.Panel4:=TPanel.Create(frmMain);
frmMain.Panel4:=TPanel(frmMain.DBGridCtrl1.Control s[0]);
frmMain.Group:=TGroupBox.Create(frmMain);
frmMain.Group.Parent:=frmMain.Panel4;
frmMain.Group.Left:=5;
frmMain.Group.Top:=6;
frmMain.Group.Width:=620;
frmMain.Group.Height:=50;
frmMain.Lab1:=TLabel.Create(frmMain);
frmMain.Lab1.Parent:=frmMain.Group;
frmMain.Lab1.Left:=580;
frmMain.Lab1.Top:=10;
frmMain.Lab1.Width:=574;
frmMain.Lab1.Height:=10;
frmMain .Lab1.Caption :=':ÚäæÇä';
frmMain.DBTxt1:=TDBText.Create(frmMain);
frmMain.DBTxt1.Parent:=frmMain.Group;
frmMain.DBTxt1.Left:=205;
frmMain.DBTxt1.Top:=10;
frmMain.DBTxt1.Width:=369;
frmMain.DBTxt1.Height:=17;
frmMain.DBTxt1.DataField:='JobName';
frmMain.DBTxt1.DataSource:=DM.Q1DS;
frmMain.DBTxt1.Alignment:=taRightJustify;
frmMain.Lab2:=TLabel.Create(frmMain);
frmMain.Lab2.Parent:=frmMain.Group;
frmMain.Lab2.Left:=166;
frmMain.Lab2.Top:=10;
frmMain.Lab2.Width:=28;
frmMain.Lab2.Height:=13;
frmMain .Lab2.Caption :=':ÊáÝä';
frmMain.DBTxt2:=TDBText.Create(frmMain);
frmMain.DBTxt2.Parent:=frmMain.Group;
frmMain.DBTxt2.Left:=95;
frmMain.DBTxt2.Top:=10;
frmMain.DBTxt2.Width:=65;
frmMain.DBTxt2.Height:=17;
frmMain.DBTxt2.DataField:='Tel';
frmMain.DBTxt2.DataSource:=DM.Q1DS;
frmMain.DBTxt2.Alignment:=taRightJustify;
frmMain.Lab3:=TLabel.Create(frmMain);
frmMain.Lab3.Parent:=frmMain.Group;
frmMain.Lab3.Left:=69;
frmMain.Lab3.Top:=9;
frmMain.Lab3.Width:=32;
frmMain.Lab3.Height:=13;
frmMain .Lab3.Caption :=':ݘÓ';
frmMain.DBTxt3:=TDBText.Create(frmMain);
frmMain.DBTxt3.Parent:=frmMain.Group;
frmMain.DBTxt3.Left:=6;
frmMain.DBTxt3.Top:=8;
frmMain.DBTxt3.Width:=56;
frmMain.DBTxt3.Height:=17;
frmMain.DBTxt3.DataField:='Fax';
frmMain.DBTxt3.DataSource:=DM.Q1DS;
frmMain.DBTxt3.Alignment:=taRightJustify;
frmMain.Lab4:=TLabel.Create(frmMain);
frmMain.Lab4.Parent:=frmMain.Group;
frmMain.Lab4.Left:=580;
frmMain.Lab4.Top:=26;
frmMain.Lab4.Width:=32;
frmMain.Lab4.Height:=13;
frmMain .Lab4.Caption :=':ÂÏÑÓ';
frmMain.DBTxt4:=TDBText.Create(frmMain);
frmMain.DBTxt4.Parent:=frmMain.Group;
frmMain.DBTxt4.Left:=128;
frmMain.DBTxt4.Top:=27;
frmMain.DBTxt4.Width:=445;
frmMain.DBTxt4.Height:=17;
frmMain.DBTxt4.DataField:='Address';
frmMain.DBTxt4.DataSource:=DM.Q1DS;
frmMain.DBTxt4.Alignment:=taRightJustify;
frmMain.Lab5:=TLabel.Create(frmMain);
frmMain.Lab5.Parent:=frmMain.Group;
frmMain.Lab5.Left:=80;
frmMain.Lab5.Top:=25;
frmMain.Lab5.Width:=51;
frmMain.Lab5.Height:=13;
frmMain .Lab5.Caption :=':˜Ï ÓÊí';
frmMain.DBTxt5:=TDBText.Create(frmMain);
frmMain.DBTxt5.Parent:=frmMain.Group;
frmMain.DBTxt5.Left:=2;
frmMain.DBTxt5.Top:=25;
frmMain.DBTxt5.Width:=57;
frmMain.DBTxt5.Height:=17;
frmMain.DBTxt5.DataField:='PostalCode';
frmMain.DBTxt5.DataSource:=DM.Q1DS;
frmMain.DBTxt5.Alignment:=taRightJustify;
frmMain.Vis:=1;
end
else if DM.Q1['PageType']=5 then
begin
// if frmMain.Vis=1 then
// frmMain.Panel.Destroy;
// frmMain.PageID:= DM.Q2['PageID'];
dir := GetCurrentDir ;
frmMain.Panel:=TPanel.Create(nil);
frmMain.Panel.Parent:=frmMain;
frmMain.Panel.Left:=180;
frmMain.Panel.Top:=240;
frmMain.Panel.Width:=650;
frmMain.Panel.Height:=430;
frmMain.Panel.BevelOuter:=bvNone;
frmMain.Panel.Color:=clWhite;
frmMain.Flash:=TShockwaveFlash.Create(frmMain);
frmMain.Flash.Parent:=frmMain.Panel;
frmMain.Flash.Width:=650;
frmMain.Flash.Height:=430;
frmMain.Flash.Left:=0;
frmMain.Flash.Top:=0;
dir := GetCurrentDir ;

if FindFirst(dir+'\'+DM.Q1['PageText'], faAnyFile, sr ) = 0 then
result := Int64(sr.FindData.nFileSizeHigh) shl Int64(32) + Int64(sr.FindData.nFileSizeLow)
else
result := -1;
FindClose(sr) ;
if Int64(strtoint(DM.Q1['PageParam']))=result then
begin
frmMain.Flash.Show;
frmMain.Flash.Movie:=dir+'\'+DM.Q1['PageText'];
end;
//frmMain.Label7.Caption:=inttostr(result);
frmMain.Vis:=1;
end
else if DM.Q1['PageType']=2 then
begin
//if frmMain.Vis=1 then
// frmMain.Panel.Destroy;
//frmMain.PageID:= DM.Q2['PageID'];
Param:=DM.Q1['PageParam'];
DM.Q1.Close ;
DM.Q1.SQL.Clear ;
DM.Q1.SQL.Add('Select * from tbl_jobCategory where CategoryParent=:ID') ;
DM.Q1.Parameters.ParamByName('ID').Value:=Param;
DM.Q1.Open ;
//frmMain.Label7.Caption:=inttostr(DM.Q1.RecordCount );
frmMain.Panel:=TPanel.Create(frmMain);
frmMain.Panel.Parent:=frmMain;
frmMain.Panel.Left:=180;
frmMain.Panel.Top:=240;
frmMain.Panel.Width:=650;
frmMain.Panel.Height:=430;
frmMain.Panel.BevelOuter:=bvNone;
frmMain.Panel.Color:=clWhite;
frmMain.DBGridCtrl1:=TDBCtrlGrid.Create(frmMain);
frmMain.DBGridCtrl1.Parent:=frmMain.Panel;
frmMain.DBGridCtrl1.Left:=1;
frmMain.DBGridCtrl1.Top:=10;
frmMain.DBGridCtrl1.Width:=645;
frmMain.DBGridCtrl1.DataSource:=DM.Q1DS ;
frmMain.DBGridCtrl1.PanelHeight:=72;
//frmMain.DBGridCtrl1.PanelBorder:=gbNone;
frmMain.DBGridCtrl1.RowCount:=5;
frmMain.Panel:=TPanel.Create(frmMain);
frmMain.Panel:=TPanel(frmMain.DBGridCtrl1.Controls[0]);
frmMain.Group:=TGroupBox.Create(frmMain);
frmMain.Group.Parent:=frmMain.Panel;
frmMain.Group.Left:=5;
frmMain.Group.Top:=6;
frmMain.Group.Width:=620;
frmMain.Group.Height:=50;
frmMain.Lab1:=TLabel.Create(frmMain);
frmMain.Lab1.Parent:=frmMain.Group;
frmMain.Lab1.Left:=580;
frmMain.Lab1.Top:=10;
frmMain.Lab1.Width:=574;
frmMain.Lab1.Height:=10;
frmMain.Lab1.Caption :=':ÚäæÇä';
frmMain.DBTxt1:=TDBText.Create(frmMain);
frmMain.DBTxt1.Parent:=frmMain.Group;
frmMain.DBTxt1.Left:=205;
frmMain.DBTxt1.Top:=10;
frmMain.DBTxt1.Width:=369;
frmMain.DBTxt1.Height:=17;
frmMain.DBTxt1.DataField:='CategoryName';
frmMain.DBTxt1.DataSource:=DM.Q1DS;
frmMain.DBTxt1.Alignment:=taRightJustify;
frmMain.Vis:=1;
end
else if DM.Q1['PageType']=32 then
begin
//if frmMain.Vis=1 then
// frmMain.Panel.Destroy;
//frmMain.PageID:= DM.Q2['PageID'];
Param:=DM.Q1['PageParam'];
DM.Q3.Close ;
DM.Q3.SQL.Clear ;
DM.Q3.SQL.Add('Select * from tbl_jobCategory where CategoryParent=:IDP') ;
DM.Q3.Parameters.ParamByName('IDP').Value:=Param;
DM.Q3.Open ;
//frmMain.Label7.Caption:=inttostr(DM.Q3.RecordCount );
frmMain.Panel:=TPanel.Create(frmMain);
frmMain.Panel.Parent:=frmMain;
frmMain.Panel.Left:=180;
frmMain.Panel.Top:=240;
frmMain.Panel.Width:=650;
frmMain.Panel.Height:=430;
frmMain.Panel.BevelOuter:=bvNone;
frmMain.Panel.Color:=clWhite;
frmMain.ScrollBox:=TScrollBox.Create(frmMain);
frmMain.ScrollBox.Parent:=frmMain.Panel;
frmMain.ScrollBox.Left:=0;
frmMain.ScrollBox.Top:=0;
frmMain.ScrollBox.Width:=650;
frmMain.ScrollBox.Height:=430;
frmMain.ScrollBox.BorderStyle:=bsNone;
SetLength(frmMain.Image,DM.Q3.RecordCount);
b:=10;
c:=10;
DM.Q3.First;
for i:=0 to DM.Q3.RecordCount-1 do
begin
frmMain.Image[i]:=TImage.Create(frmMain);
frmMain.Image[i].Parent :=frmMain.ScrollBox;
frmMain.Image[i].Left:=c;
frmMain.Image[i].Top:=b;
c:=c+120;
if c>=640 then
begin
c:=10;
b:=b+120;
end;
frmMain.Image[i].Width:=100;
frmMain.Image[i].Height:=100;
frmMain.Image[i].Stretch:=true;
frmMain.Image[i].Hint:=DM.Q3CategoryName.Value;
frmMain.Image[i].ShowHint:=true;
frmMain.Image[i].OnClick:=frmMain.ImgClick;
frmMain.Image[i].Cursor:=crHandPoint;
frmMain.Image[i].Tag:=DM.Q3PageID.Value;
if Dm.Q3ImageType.AsString <> '' then
begin
BlobStream := DM.Q3.CreateBlobStream(Dm.Q3CategoryPic, bmRead);
try
Ext := UpperCase(Dm.Q3ImageType.AsString);
if Ext = '.BMP' then
frmMain.Image[i].Picture.Bitmap.LoadFromStream(BlobStream)
else if Ext = '.JPG' then
begin
JPEGImage := TJPEGImage.Create;
try
JPEGImage.LoadFromStream(BlobStream);
frmMain.Image[i].Picture.Assign(JPEGImage);
finally
JPEGImage.Free;
end;
end;
finally
BlobStream.Free;
end;
end
else
frmMain.Image[i].Picture := nil;

if i<>DM.Q3.RecordCount-1 then
DM.Q3.Next;
end;
frmMain.Vis:=1;
end
else if DM.Q1['PageType']=31 then
begin
//if frmMain.Vis=1 then
// frmMain.Panel.Destroy;
//frmMain.PageID:= DM.Q2['PageID'];
Param:=DM.Q1['PageParam'];
DM.Q3.Close ;
DM.Q3.SQL.Clear ;
DM.Q3.SQL.Add('Select * from tbl_jobCategory where CategoryParent=:IDP') ;
DM.Q3.Parameters.ParamByName('IDP').Value:=Param;
DM.Q3.Open ;
//frmMain.Label7.Caption:=inttostr(DM.Q3.RecordCount );
frmMain.Panel:=TPanel.Create(frmMain);
frmMain.Panel.Parent:=frmMain;
frmMain.Panel.Left:=180;
frmMain.Panel.Top:=240;
frmMain.Panel.Width:=650;
frmMain.Panel.Height:=430;
frmMain.Panel.BevelOuter:=bvNone;
frmMain.Panel.Color:=clWhite;
frmMain.ScrollBox:=TScrollBox.Create(frmMain);
frmMain.ScrollBox.Parent:=frmMain.Panel;
frmMain.ScrollBox.Left:=0;
frmMain.ScrollBox.Top:=0;
frmMain.ScrollBox.Width:=650;
frmMain.ScrollBox.Height:=430;
frmMain.ScrollBox.BorderStyle:=bsNone;
SetLength(frmMain.Image3,DM.Q3.RecordCount);
b:=20;
c:=20;
DM.Q3.First;
for i:=0 to DM.Q3.RecordCount-1 do
begin
frmMain.Image3[i]:=TImage.Create(frmMain);
frmMain.Image3[i].Parent :=frmMain.ScrollBox;
frmMain.Image3[i].Left:=c;
frmMain.Image3[i].Top:=b;
c:=c+120;
if c>=510 then
begin
c:=20;
b:=b+120;
end;
frmMain.Image3[i].Width:=100;
frmMain.Image3[i].Height:=100;
frmMain.Image3[i].Stretch:=true;
frmMain.Image3[i].Hint:=DM.Q3CategoryName.Value;
frmMain.Image3[i].ShowHint:=true;
frmMain.Image3[i].OnClick:=frmMain.ImgClick;
frmMain.Image3[i].Cursor:=crHandPoint;
if Dm.Q3ImageType.AsString <> '' then
begin
BlobStream := DM.Q3.CreateBlobStream(Dm.Q3CategoryPic, bmRead);
try
Ext := UpperCase(Dm.Q3ImageType.AsString);
if Ext = '.BMP' then
frmMain.Image3[i].Picture.Bitmap.LoadFromStream(BlobStream)
else if Ext = '.JPG' then
begin
JPEGImage := TJPEGImage.Create;
try
JPEGImage.LoadFromStream(BlobStream);
frmMain.Image3[i].Picture.Assign(JPEGImage);
finally
JPEGImage.Free;
end;
end;
finally
BlobStream.Free;
end;
end
else
frmMain.Image3[i].Picture := nil;

if i<>DM.Q3.RecordCount-1 then
DM.Q3.Next;
end;

frmMain.Vis:=1;
end;
end;
end;
end.


فراخوانی این کلاس به این صورت انجام می شده

var Page:Raak_Page;
CAdv:Raak_Adv;
begin
if frmMain.Vis=1 then
begin
frmMain.Panel.Destroy;
frmMain.Vis:=0;
end;
CAdv:=Raak_Adv.create;
Page:=Raak_Page.create;
Page.ShowPage(DM.Q2['PageID']);
CAdv.ShowImage1;
CAdv.ShowImage2;

vcldeveloper
چهارشنبه 05 مرداد 1390, 02:10 صبح
خب، این کدی که شما نوشتید، هم از نظر طراحی و هم از نظر پیاده سازی مشکل داره. از نظر طراحی، اولا اصلا لزومی نداشت که همچین کلاسی از TCustomControl مشتق بشه. این کلاس خودش هیچ رابط گرافیکی کاربری نداره که بخواد از TCustomControl مشتق بشه. همچنین این کلاس داره مستقیما با یک شی ایی به نام frmMain تعامل برقرار میکنه که هم این شکل از تعامل بین اشیاء غلط هست، و هم این نوع تغییر وضعیت یک شی توسط شی دیگه.
کلاس Raak_Page بر فرض اگر نیازی به شی frmMain داشت، باید یک فیلد از نوع TfrmMain در داخل خودش تعریف می کرد، و از طریق متد سازنده یا یکی از خصوصیاتش به این فیلد مقدار داده میشد، تا این کلاس کار مورد نظر خودش را روی شی مربوطه اعمال کنه. الان این کلاس برای خودش فرض گرفته که همیشه یک شی ایی با نام frmMain آماده هست، و میشه هر وقت که خواستیم، بهش دسترسی داشته باشیم و وضعیتش را تغییر بدیم. برای استفاده از DM هم وضع مشابه استفاده از frmMain هست.
همچنین، همانطور که قبلا هم گفتم، کل کار رو کلاس Raak_Page ایجاد یک سری کنترل روی شی frmMain هست، و کار دیگه ایی انجام نمیده. این کار باید در داخل کلاس TfrmMain انجام میشد، نه در یک کلاس جداگانه. در واقع کل این کار شما معادل ایجاد یک متد جدید در TfrmMain با نام ShowPage، و قراردادن این کدها درون آن هست.

اما از نظر پیاده سازی؛ اولا به جای اینکه متد سازنده مربوط به کلاس والد (TCustomControl) در این کلاس override بشه، رفتید یک متد سازنده خالی تعریف کردید که متد سازنده والد را هم فراخوانی نمیکنه، یعنی عملا کلاس های والد این کلاس کلا مقدار دهی اولیه نمیشند. اون متد Create شما در اون کلاس کاملا بی مصرف هست. ثانیا، کد از نظر پیاده سازی بیخودی طولانی شده و اگر پیچیدگی اش محاسبه بشه، پیچیدگی اش بالا ست. همچین کدی باید به بخش های کوچکتری تقسیم بشه که هم خواندنش راحتر باشه و هم نگهداری ازش. ثالثا، به خصوصیت SQL مربوط به کوئری ها در هر بار اجرای کد مقدار داده میشه که این کار استفاده از پارامترها در SQL را بی استفاده میکنه. برای استفاده بهینه از پارامترها در SQL، باید دستور SQL یک بار نوشته بشه، و در اجراهای متعدد فقط مقدار پارامترها تغییر کنه، نه اینکه هر بار کل SQL مجددا نوشته بشه. این کار باعث میشه که با هر بار اجرای این کد، دستور SQL مربوطه مجددا توسط بانک اطلاعاتی parse و آماده اجرا بشه. رابعا، برای آزاد کردن یک شی همیشه از متد Free استفاده کنید، نه از متد Destroy. خامسا، سعی کنید برای حفظ خوانایی کدتان، از مقادیر ثابت با معنی، و متغیرهای با نام مناسب استفاده کنید. مثلا یک برنامه نویس با خواندن کد:

DM.Q1['PageType']=31
متوجه نمیشه که منظور از 31 چی هست، اما اگر به جای آن، یک داده enumerator یا یک ثابت عددی تعریف می کردید، مثلا به این شکل:

const
PT_JobCategory = 31;
اون وقت می تونستید در کد خودتان به جای 31 از این ثابت عددی استفاده کنید، و هر کی با دیدن این کد متوجه میشد که اینجا منظور از اون مقایسه چی هست. همین مسئله برای فیلد TfrmMain.Vis هم صادقه. می تونستید به جای اون فیلد، یک فیلد Boolean تعریف کنید با نام IsVisible ( یا هر اسم دیگه ایی که معنی مورد نظر شما را برسونه). اون وقت کد فرضی شما میشد شبیه به این:


if frmMain.IsVisible then
begin
frmMain.IsVisble := False;
FreeAndNil(frmMain.Panel);
end;
که خوانایی بالاتری نسبت به کد شما داره.

موارد دیگه ایی هم ممکنه باشه، من فرصت نکردم کد شما را خط به خط بخوانم. در هر حال، برگردیم به مشکلی که اعلام کردید، توی این کدها مشخص نیست که چه شی ایی آزاد شد که مجددا داره بهش ارجاع داده میشه. frmMain و frmMain.Panel می تونند کاندیداهای اصلی این مورد باشند؛ به خصوص frmMain.Panel که در جاهای مختلف کد اون رو Destroy می کنید.
برای پیدا کردن شی ایی که با ارجاع غیر معتبر موجه میشه، در داخل دیباگر دلفی وقتی Access Violation رخ میده، اجرای برنامه را Break کنید، و ببینید روی چه خطی از سورس کد متوقف میشه. روی همون خط یک Break point بذارید و برنامه را مجددا اجرا کنید. وقتی به Break point رسید، اجرای کد را خط به خط دنبال کنید، و ببینید دقیقا چه خطی باعث بروز خطا میشه، و در اون خط به چه شی ایی ارجاع داده شده؟