PDA

View Full Version : ایجاد فرم در صورت نداشتن نام آن



AmirSky
چهارشنبه 05 خرداد 1389, 18:35 عصر
باسلام
یه سوال داشتم و اون اینکه اگر نام یک فرم رو به صورت String داشته باشیم (مثلا به صورت 'form1' ) به چه شکل میتوان اون رو ایجاد کرد .

Mahmood_M
چهارشنبه 05 خرداد 1389, 18:44 عصر
سئوالتون کاملا واضح نیست !
می خواید یک فرم ایجاد کنید که نامش Form1 باشه ؟ یا اینکه فرمی به نام Form1 در پروژه دارید می خواید اون رو Create کنید ؟

لطفا توضیح بیشتر و کاملتری در مورد سئوالتون بدید ...

AmirSky
چهارشنبه 05 خرداد 1389, 19:44 عصر
فکر کنم اگه با مثال بگم بهتر باشه

( Form1 := TForm1.MyCreate( S,Form2

میخوام در Form1 بعد از ایجاد شدن در قسمتی از آن فرم Form2 ایجاد شود
و یک موردی که فعلا نیاز فوری ندارم اینه که اگر ورودی Form2 به صورت String باشه بهتره


ممنون

vcldeveloper
چهارشنبه 05 خرداد 1389, 20:08 عصر
برای چه کاری میخواید اون رو استفاده کنید؟ اگر فقط میخواید اون فرم Create بشه، می تونید به شکل زیر عمل کنید:

function CreateFormByName(const FormName: string): TForm;
var
FormClass : TPersistentClass;
begin
Result := nil;
FormClass := GetClass(FormName);
if Assigned(FormClass) then
begin
Result := TForm(FormClass.NewInstance);
Result.Create(Application);
end;
end;

برای اینکه کد بالا کار کنه،کلاس مربوطه باید Register شده باشه، فرم هایی که در داخل IDE برای پروژه ایجاد می کنید، به طور خودکار Register میشند. اما برای سایر فرم ها، باید خودتان کلاس آنها را رجیستر کنید، مثلا در بخش Initialization یونیت مربوط به اون فرم:
initialization
RegisterClass(TMyForm);

مثالی از استفاده از این کد:
CreateFormByName('TForm1').Show;

البته در کد بالا، شما به خصوصیات و متدهای اختصاصی کلاس TForm1 دسترسی ندارید، چون خروجی به TForm که کلاس پایه فرم های دلفی هست، Type-cast شده. در نتیجه فقط به متدها و خصوصیات ارائه شده توسط TForm برای کلاس های فرزندش دسترسی دارید.

اگر میخواید به خصوصیات و متدهای کلاس مورد نظرتان هم دسترسی داشته باشید، اون وقت باید از RTTI دلفی استفاده کنید. شما مشخص نکردید که دقیقا برای چه کاری به این کد نیاز دارید.

مهران رسا
چهارشنبه 05 خرداد 1389, 20:26 عصر
سلام؛
آقای کشاورز چرا در خط 5 مقدار Result برابر nil قرار گرفته ؟

zidane
چهارشنبه 05 خرداد 1389, 21:28 عصر
احتمالا به این خاطر هست که اگر در داخل IF مقداری برای آن تعیین نشد، مقدار اولیه داشته باشه

مهران رسا
چهارشنبه 05 خرداد 1389, 21:45 عصر
احتمالا به این خاطر هست که اگر در داخل IF مقداری برای آن تعیین نشد، مقدار اولیه داشته باشه
خب مگه موقع تعریف مقداری جز nil داره ؟

مصطفی ساتکی
چهارشنبه 05 خرداد 1389, 21:46 عصر
آقای کشاورز دقت نفرمودید ایشون گفتند نام Form نه نام Class بایستی به این صورت نوشته می شد.

function CreateFormByNameEX(AFormName : String):tform;
var
FC : TFormClass;
H : HWND;

ClsName : array[0..255] of char;
ClsNamestr : string;
begin
H := FindWindow(nil,pchar(AFormName));
GetClassName(H,ClsName,256);
ClsNamestr := ClsName;
FC := TFormClass(FindClass(ClsNamestr));
Result := FC.Create(Application);


end;
procedure TForm2.Button1Click(Sender: TObject);
begin
CreateFormByName('Form3').Show;
end;
initialization RegisterClass(TMyForm);

vcldeveloper
چهارشنبه 05 خرداد 1389, 22:27 عصر
آقای کشاورز دقت نفرمودید ایشون گفتند نام Form نه نام Class بایستی به این صورت نوشته می شد.نام یک فرم بخشی از خصوصیات یک Instance هست. تا زمانی هم که یک Instance ایجاد نشده باشه، خصوصیات آن تعیین شده نیستند. پس لازمه اینکه شما نام یک کنترل را در Runtime داشته باشید، این هست که شی مربوطه ایجاد شده باشه.
کاری که کد شما میکنه اینه که نام کلاس یک پنجره ایی که از قبل وجود داره را بر اساس Caption اون پنجره پیدا میکنه، و از همون کلاس یک Instance جدید درست میکنه. مشکلش هم این هست که اولا با این کد شما، باید حداقل یک بار از اون کلاس یک Instance ایجاد شده باشه، تا بشه از روی اون Instance، مقدار Caption اون رو به دست آورد. ثانیا، Caption یک فرم لزوما مساوی نام آن فرم (خصوصیت Name آن) نیست.

پس کد شما چیزی به بحث اضافه نمیکنه. برای ساخت یک شی در Runtime، حداقل چیزی که باید داشته باشید، نام Type مربوط به اون شی هست.


پی نوشت: این نکته رو هم اضافه کنم که در دلفی به طور پیش فرض IDE نام کلاس یک فرم را از روی مقدار خصوصیت Name آن میسازه (با اضافه کردن T به ابتدای نام فرم)، پس اگر هم لازم بود نام فرم به عنوان ورودی تابع استفاده بشه، میشد به ابتدای مقدار پارامتر ورودی تابع یک T اضافه کرد، تا نام کلاس به دست بیاد. به عنوان مثال، اگر نام فرم Form1 باشه، کلاسی که IDE به طور پیش فرض تولید میکنه، TForm1 هست.

موفق باشید

AmirSky
چهارشنبه 05 خرداد 1389, 22:36 عصر
هر دو موردی که آقایان Delphi_CAT و علی کشاورز گفته بودند رو تست کردم و به مشکل خوردم.

اولا در مورد ( initialization RegisterClass(TMyFormاز این کد استفاده کردم مشکل داشت
و بهتره منظورم رو بیشتر بیان کنم .
ببینید دوستان من ابتدا قصد دارم یک فرم رو ایجاد کنم که این فرم از طریق یک یونیت ساخته شده و در فرم ها و برنامه های زیادی مورد استفاده قرار می گیرد و تقریبا دستور آن به این شکل است
( Form1 := TForm1.MyCreate( S,Form2
البته در قسمت MyCreate کد های بیشتری قرار دارد که از سوال خارج است
و کاری که من میخواهم انجام دهم این است که وقتی Form1 ایجاد شد درون آن یک فرضا دکمه ای وجود داشته باشد که فرم دیگری (فرضا Form2)ساخته شود . پس در constructor ای که Form1 را بوجود می آورد Form2 را باید به صورت String یا TForm دریافت نمود
اما در هنگام ایجاد Form2 که می تواند قبلاً توسط من ساخته شده باشد مشکل دارم
امیدوارم منظورم رو بهتر گفته باشم
ممنون

vcldeveloper
چهارشنبه 05 خرداد 1389, 22:44 عصر
خب مگه موقع تعریف مقداری جز nil داره ؟ ممکنه مقداری غیر از Nil داشته باشه. کامپایلر دلفی متغیرهای تعریف شده در داخل تابع را مقداردهی اولیه نمیکنه. اگر اون خط رو از کد حذف کنید، یک Warning از کامپایلر دریافت می کنید، چون در صورت برقرار نبودن شرط در خط 7، مقدار خروجی تابع مشخص نیست. یک راه برای برطرف کردن اون Warning این بود که یک گزاره else به شرط مربوطه اضافه بشه، اما نوشتن آن در خط 5 مطمئن تر هست، چون حتی اگر مشکلی در اجرای تابع GetClass هم پیش بیاد، باز مقدار برگشتی شما nil هست، نه یک مقدار تعریف نشده.



به مشکل خوردم.وقتی به مشکل بر می خورید، باید بگید که چی نوشتید، و به چه مشکلی برخوردید.


اولا در مورد ( initialization RegisterClass(TMyFormاز این کد استفاده کردم مشکل داشتاون کد به عنوان نمونه برای شما گذاشته شد که ببینید چطور یک کلاس رو می تونید Register کنید، نه اینکه اون رو به همون شکل Copy\Paste کنید! این کد باید در همان یونیتی که فرم مورد نظر شما (با توضیحات شما فرم Form2) قرار داره، نوشته بشه. ثانیا، به جای TMyForm باید نام کلاس فرم خودتان را بنویسید (با توضیحات شما، نام کلاس فرم شما TForm2 هست).

AmirSky
چهارشنبه 05 خرداد 1389, 22:57 عصر
این دستور (initialization RegisterClass(TForm2 در هر دو فرم قرار دادم ولی فایده ای نداشت
و در مورد کدی که شما آقای کشاورز گفته بودید پیغام Access violation صادر می شود و منظور من از مشکل همین بود
ببینید Form2 قبلا توسط من ایجاد شده فقط توسط Form1 باید Create شود

vcldeveloper
پنج شنبه 06 خرداد 1389, 02:25 صبح
این دستور (initialization RegisterClass(TForm2 در هر دو فرم قرار دادم ولی فایده ای نداشت دوست عزیز، نقل و نبات نیست که همینطوری هر جا اضافه کنید، فقط در یونیت مربوط به Form2 آن را اضافه کنید.


و در مورد کدی که شما آقای کشاورز گفته بودید پیغام Access violation صادر می شود و منظور من از مشکل همین بودهزار و یک چیز می تونند موجب Access Violation بشند، چه کدی نوشتید؟ چطور آن را فراخوانی کردید، در چه شرایطی پیام خطا ایجاد میشه؟ وقتی پیام خطا ظاهر میشه، و اجرای برنامه را Break می کنید، روی چه خطی از سورس کد قرار میگیره؟


ببینید Form2 قبلا توسط من ایجاد شده فقط توسط Form1 باید Create شود ایجاد شده، یعنی Create شده! منظورتون چی هست که این فرم توسط شما ایجاد شده، فقط باید Create بشه؟! اگر منظورتون این هست که Form2 را در IDE طراحی کردید، و باید در زمان اجرا Create بشه، راه حلی که در پست های قبلی بهش اشاره کردم، مشکلی نداره. اگر شما در استفاده از آن مشکل دارید، کدی اینجا بذارید که از همون راه حل استفاده میکنه، و به خطا منجر میشه، تا بشه فهمید مشکل شما کجا ست.

در ضمن، سورسی که اینجا قرار میگیره را همینطوری Copy\Paste نکنید توی کد برنامه خودتان، آن را بخوانید، نحوه عملکردش را متوجه بشید، بعد ازش استفاده کنید، یا متناسب با شرایط پروژه خودتان، آن را برای خودتان بهینه کنید.

AmirSky
پنج شنبه 06 خرداد 1389, 09:36 صبح
یک نمونه خیلی ساده درست کردم و از تابعی که گفته بودید استفاده کردم
مشکلات دیشب رو نداره و دلیلش رو بعدا باید بررسی کنم
فقط در این نمونه فکر می کنم مشکل در نمایش Form2 باشه

49796

ممنون می شم اگر لطف کنید و بگید مشکل از کجاست.

vcldeveloper
پنج شنبه 06 خرداد 1389, 16:24 عصر
فقط در این نمونه فکر می کنم مشکل در نمایش Form2 باشه
مشکل کد شما دو چیز هست:
اولا در پست های قبلی توضیح دادم که کدی که گذاشتم، نام کلاس فرم مورد نظر را دریافت میکنه، نه نام فرم را. اگر میخواید نام فرم ورودی تابع باشه، به ابتدای مقدار پارامتر ورودی کارکتر T را اضافه کنید. اگر نام فرم شما Form2 هست، نام کلاسی که براتون ساخته میشه، TForm2 هست. حالا به عنوان مقدار ورودی تابع، یا باید TForm2 را وارد کنید، یا اینکه همان Form2 را به تابع ارسال کنید، و در داخل تابع یک T به ابتدای آن اضافه کنید که بشه TForm2.

ثانیا، فرمی که Create شده، برای اینکه نمایش داده بشه، باید متد Show آن فراخوانی بشه، که شما آن را فراخوانی نکردید.

کد اصلاح شده شما را ضمیمه کردم.

AmirSky
پنج شنبه 06 خرداد 1389, 20:37 عصر
از شما دوست عزیز بسیار ممنونم
تابعی که گذاشته بودید رو درست متوجه نشده بودم
مشکل من حل شد