تنفيذ النوافذ العادية في دلفي
ملخص في مكتبة VCL في Delphi ، لراحة الاستخدام والتنفيذ ، ينشئ تطبيق كائن التطبيق نافذة مخفية لمعالجة استجابات الرسائل. هذه النافذة التي تجعل البرامج التي تم تطويرها باستخدام VCL مشوهًا إلى حد ما ، مثل عدم القدرة على الترتيب والبلاط بشكل طبيعي مع النوافذ الأخرى. من خلال التحليل المتعمق لـ VCL ، توفر هذه المقالة حلاً يمكنه حل المشكلة عن طريق تعديل 3 أسطر من التعليمات البرمجية فقط إلى ملف مشروع التطبيق ، دون أي تغييرات على طريقة البرمجة الأصلية.
الكلمة الرئيسية VCL ، النافذة العادية ، التطبيع
1 مقدمة
تحتوي تطبيقات Windows المكتوبة في مكتبة فئة VCL التي توفرها Delphi على ميزة مميزة تختلف بوضوح عن نافذة Windows القياسية - تختلف قائمة النظام للنافذة الرئيسية عن قائمة النظام على شريط المهام. بشكل عام ، تحتوي قائمة النظام في النافذة الرئيسية على ستة عناصر القائمة ، بينما تحتوي قائمة نظام شريط المهام على ثلاثة عناصر فقط. في الاستخدام الفعلي ، وجدنا أن البرامج التي تم تطويرها باستخدام VCL لها الإحراج التالي:
1) ليست جميلة بما فيه الكفاية. هذا مؤكد ، إذا لم يتطابق مع المعايير ، فسيظهر بشكل طبيعي مشوهًا بعض الشيء.
2) لا يوجد تأثير للرسوم المتحركة عندما يتم تقليل النافذة الرئيسية.
3) لا يمكن ترتيب النافذة والبلاط بشكل طبيعي مع النوافذ الأخرى.
4) قائمة نظام شريط المهام لها أولوية قصوى. في وجود نافذة مشروطة ، لا يزال من الممكن تقليل البرنامج بأكمله ، على عكس تصميم النافذة المشروطة.
تم حل مشكلة تقليل تأثيرات الرسوم المتحركة في النافذة الرئيسية من خلال وظيفة simwinnoanimate في الأشكال. على الرغم من أن هذا لن يكون له أي تأثير على التطبيق في معظم الحالات ، إلا أنه غير مقبول بالفعل في بعض الحالات التي يتم فيها متابعة الآثار المهنية. نظرًا لأن C ++ Builder و Delphi يستخدمان نفس المجموعة من مكتبات الفصل ، فإن المشكلات المذكورة أعلاه موجودة أيضًا في تطبيقات Windows المكتوبة باستخدام C ++ Builder.
لقد ناقشت هذه المسألة في المقالات السابقة (يمكن العثور عليها في منزل Forrest Gump) ، ويبدو أن السرد في ذلك الوقت خدعة في الأساس ، ووجدت هذه الطريقة بالصدفة. تتمثل مهمة هذه المقالة في تحليل مكتبة فئة VCL لشرح مبدأ القيام بذلك ، ثم إعطاء طريقة تستخدم فقط 3 أسطر من الكود لحل مشكلة "النافذة غير الطبيعية" تمامًا في دلفي.
2 مبدأ
2.1 عملية إنشاء التطبيق
فيما يلي ملف مشروع تطبيق Delphi.
برنامج Project1 ؛
يستخدم
الأشكال ،
unit1 في 'unit1.pas' {form1} ؛
{$ r *.res}
يبدأ
application.initialize ؛
application.createform (tform1 ، form1) ؛
application.run ؛
نهاية .
يتم إنشاء النافذة المخفية بواسطة كائن التطبيق ، فمن أين يأتي كائن التطبيق؟ اضغط مع الاستمرار على CTRL في نافذة تحرير رمز Delphi وانقر فوق التطبيق ، ستجد أن كائن التطبيق هو واحد من العديد من الكائنات العالمية المحددة في وحدة Forms.Pas. هذا لا يكفي ، ما نريد معرفته هو المكان الذي تم فيه إنشاء كائن التطبيق ، لأنه يجب إنشاء مثيل لفئة tapplication قبل أن نتمكن من الرجوع إليه.
فكر في الأمر ، هل هناك أي رمز سيتم تنفيذه قبل application.initialize؟ بالمناسبة ، هو الرمز في قطاع رمز التهيئة. بعد تصحيح رمز مصدر VCL بعناية ، يمكنك معرفة أن العديد من الوحدات في VCL لديها شرائح رمز التهيئة. جميع إجراءات التهيئة.
البحث في دليل رمز المصدر VCL مع الكلمة الرئيسية "tapplication.create" ، وجدنا الرمز لإنشاء كائن التطبيق في وحدة Controls.pas. في قطاع رمز التهيئة من وحدة Controls.Pas ، هناك دعوة لإجراء initControls ، وتنفيذ initControls كما يلي:
ضوابط الوحدة
...
التهيئة
...
initControls ؛
الإجراء initControls ؛
يبدأ
...
الماوس: = tmouse.create ؛
الشاشة: = tscreen.create ( لا شيء ) ؛
التطبيق: = tapplication.create ( nil ) ؛
...
نهاية ؛
حسنًا ، في هذه المرحلة ، أكمل تحليلنا الخطوة الأولى ، لأنه لحل مشكلة النوافذ غير الطبيعية ، يجب أن نفعل شيئًا واحدًا قبل تهيئة كائن التطبيق ، لذلك من المهم للغاية فهم عملية التهيئة للتطبيق.
2.2 متغيرات islibrary
يعد متغير ISLIBRARY أحد متغيرات العلم العالمية المحددة في وحدة SYSTEM.PAS. إذا كانت قيمة islibrary صحيحة ، فهذا يعني أن وحدة البرنامج هي مكتبة ارتباط ديناميكية ، وإلا فهو برنامج قابل للتنفيذ. بعض العمليات في مكتبة فئة VCL تكمل إجراءات مختلفة بناءً على قيم مختلفة من متغير العلامة هذا. وهذا يعني أن هذا المتغير يلعب دورًا رئيسيًا في حل مشكلة النافذة غير الطبيعية في دلفي.
كما ذكرنا سابقًا ، للراحة ، تم إنشاء نافذة غير مرئية عند تهيئة كائن التطبيق (أي ، النافذة ذات "tapplication" كما هو اسم الفصل مع أدوات مثل spy ++) ، ولكنه أيضًا بسبب هذه النافذة غير المرئية تظهر البرامج التي تم تطويرها مع دلفي العديد من التشوهات. حسنًا ، إذا استطعنا إزالة هذه النافذة غير المرئية (وإزالة قائمة نظام شريط المهام في نفس الوقت) واستبدالها بنافذة التطبيق الرئيسية الخاصة بنا ، ألن يتم حل جميع المشكلات؟
من السهل القول ، ولكن هل يتطلب إجراء عملية جراحية كبيرة لتنفيذ رمز مصدر VCL؟ ألن يكون ذلك قليلاً من وضع العربة أمام الحصان؟ بالطبع الجواب هو لا ، وإلا فإن هذا المقال لم يكن متاحًا. ما أريد أن أقوله هنا هو أنه في التحليل التالي ، سنرى أن ما يسمى "طريقة البرمجة تكمن في عقل واحد" ، وممارسة زراعة الصفصاف غير المقصودة في تصميم tapplication تتركنا بالفعل مع حل لهذه المشكلة . إذا لم تقم بتحليل رمز المصدر ، فقد تضطر إلى الالتفاف في دوائر ، ولكن في الواقع سنرى أن تصميم العبقري لا يتركنا أكثر أو أقل ، تمامًا.
افتح إنشاء مُنشئ من فئة Tapplication وسوف نجد خطًا من الرمز.
مُنشئ tapplication.create (aleener: tcomponent) ؛
يبدأ
...
إن لم يكن islibrary ثم createHandle ؛
...
نهاية ؛
ما يقال هنا هو أنه إذا لم تكن وحدة البرنامج مكتبة رابط ديناميكية ، فعليك تنفيذ CreateHandle ، والعمل الذي تمه CreateHandle هو كما يلي في المساعدة: "إذا لم تكن هناك نافذة تطبيق ، قم بإنشاء" ، هنا "برنامج تطبيق" النافذة "هي النافذة غير المرئية المذكورة أعلاه ، والتي هي الجاني. في فئة tapplication ، يتم استخدام متغير fhandle لحفظ مقبض النافذة الخاص به. هذا هو إكمال إجراءات مختلفة وفقًا لقيمة Islibrary ، لأنه في مكتبات الارتباطات الديناميكية ، لا تكون حلقات الرسائل مطلوبة عمومًا ، ولكن استخدام كائنات التطبيق لتطوير مكتبات الارتباطات الديناميكية مع VCL ، لذلك هنا التصميم. حسنًا ، نحتاج فقط إلى خداع كائن التطبيق ، وتعيين Islibrary إلى True قبل إنشاءه ، وتصفية تنفيذ CreateHandle وإزالة هذه النافذة المزعجة.
من الواضح أن الكود المخصص لـ ISLIBRARY يجب وضعه في قطاع رمز التهيئة لوحدة معينة. يتم إنشاء كائن التطبيق ، في ملف المشروع ، يجب علينا وضع الوحدة التي تحتوي على رمز التخصيص قبل وحدة النماذج ، على النحو التالي (على افتراض أن الوحدة تسمى unitdllexe.pas):
قالب البرنامج ؛
يستخدم
unitdllexe في 'unitdllexe.pas' ،
الأشكال ،
formmain في 'formmain.pas' {mainform} ،
...
قائمة رمز unitdllexe.pas هي كما يلي:
وحدة Unitdllexe.
واجهة
تطبيق
التهيئة
islibrary: = صحيح ؛
// أخبر كائن Applciation أن هذه مكتبة ارتباط ديناميكية ولا تحتاج إلى إنشاء نوافذ مخفية.
نهاية .
حسنًا ، قم بتجميعها وتشغيلها. النوافذ. لكن المشكلة هي أنه لا يمكن تقليل النافذة. ماذا يحدث هنا؟ لا تزال الطريقة القديمة ، اتبعها.
2.3 تقليل النافذة الرئيسية
ينتمي التقليل إلى أوامر النظام ، وفي النهاية ، يجب أن يطلق عليه وظيفة API defwindowproc لتقليل النافذة ، لذلك وجدنا الوظيفة wmsyscommand في tcustomform التي تستجيب لرسالة WM_SysCommand دون أي صعوبة ، والتي تكتب بوضوح لإعادة توجيه الرسالة إلى الحد الأدنى للتطبيق .wndproc للتعامل:
الإجراء tcustomform.wmsysCommand ( var message: twmsyscommand) ؛
يبدأ
مع رسالة تفعل
يبدأ
if (cmdtype و $ fff0 = sc_minimize) و (application.mainform = self) ثم
application.wndproc (tmessage (message))
...
نهاية ؛
نهاية ؛
في application.wndproc ، يتم استدعاء طريقة التقليل من التطبيق استجابة للرسالة التي تم تقليلها ، وبالتالي يجب أن تكون جوهر المشكلة في عملية التقليل.
الإجراء tapplication.wndproc ( var message: tmessage) ؛
...
يبدأ
...
مع رسالة تفعل
حالة MSG من
WM_SYSCOMMAND:
القضية wparam و $ fff0 من
sc_minimize: الحد الأدنى ؛
sc_restore: استعادة ؛
آخر
تقصير؛
...
نهاية ؛
أخيرًا ، ابحث عن tapplication.minimize وسوف تفهم كل شيء. لا تنتج الدعوة إلى وظيفة defwindowproc هنا أي تأثير ، لماذا؟ نظرًا لأننا خدعنا كائن التطبيق من قبل ، تم تصفية دعوة CreateHandle ولم ينشئوا النافذة اللازمة للرد على رسالة كائن التطبيق ، فإن المقبض fhandle هو 0 ، وبالطبع غير ناجح. إذا تمكنت من توجيه fhandle إلى نافذة التطبيق الرئيسية الخاصة بنا ، فسيقوم بحل المشكلة.
الإجراء tapplication.minimize ؛
يبدأ
...
defwindowproc (fhandle ، wm_syscommand ، sc_minimize ، 0) ؛
// قيمة fhandle هنا 0
...
نهاية ؛
3 التنفيذ
سمح لنا التصميم غير المقصود لعباقمة بورلاند مرة أخرى بحل المشكلة. من التحليل السابق ، نعلم أنه في مكتبة الارتباط الديناميكية التي تم تطويرها باستخدام VCL ، لا توجد نافذة مخفية لتلقي رسائل Windows (لا يتم تنفيذ CreateHandle) ، ولكن في مكتبة الارتباط الديناميكية ، إذا كنت ترغب في عرض النافذة ، فأنت بحاجة نافذة الوالدين. كيف تحل هذه المشكلة؟ يقوم مصمم VCL بتصميم متغير FHANDLE الذي يحمل مقابض النوافذ غير المرئية كما هو قابل للكتابة ، لذلك يمكننا في الواقع تعيين قيمة لـ FHALDLE لتزويد نافذة الأصل بالنافذة الفرعية التي تحتاج إلى عرض. على سبيل المثال ، في المكتبة الديناميكية لمكتبة الارتباط لعرض نموذج ، عادة ما نمرر مقبض كائن التطبيق من خلال دالة من مكتبة الارتباط الديناميكي في الملف القابل للتنفيذ للوحدة الرئيسية ونخصصه إلى التطبيق. Link Library في الملف القابل للتنفيذ للوحدة الرئيسية وقم بتعيينه إلى Application.handle من مكتبة الارتباط الديناميكي في التطبيق.
الإجراء setapplicationHandle (MainAppWND: HWND)
يبدأ
Application.Handle: = MainAppWnd ؛
نهاية ؛
حسنًا ، نظرًا لأن application.handle هو في الواقع مجرد مقبض نافذة يستخدم داخليًا للرد على الرسائل ، وقد تمت إزالة النافذة غير المرئية التي كان ينبغي إنشاءها من قبلنا ، نحتاج فقط إلى إعطاء مقبض نافذة لاستبداله يكفي مجرد إخفاء مقبض النافذة غير الضرورية في الأصل؟ أين يمكنني أن أجد مثل هذه النافذة؟ النافذة الرئيسية للتطبيق هي الخيار الأفضل ، وبالتالي فإن الكود التالي متاح.
قالب البرنامج ؛
يستخدم
unitdllexe في 'unitdllexe.pas' ،
الأشكال ،
formmain في 'formmain.pas' {mainform} ؛
{$ r *.res}
يبدأ
application.initialize ؛
application.createform (tformmain ، formmain) ؛
application.Handle: = formmain.handle ؛
application.run ؛
نهاية .
لذلك ، تم حل جميع المشاكل. لا تحتاج إلى إجراء أي تعديلات على رمز مصدر VCL ، ولا تحتاج إلى إجراء أي تعديلات على البرنامج الأصلي. من ثلاثة أسطر من التعليمات البرمجية لجعل نافذة التطبيق الخاصة بك أمر طبيعي تمامًا مثل أي نافذة ويندوز القياسية.
1) شريط المهام وشريط عنوان النافذة لهما قوائم نظام متسقة.
2) هناك تأثير للرسوم المتحركة عندما يتم تقليل النافذة الرئيسية.
3) يمكن ترتيب النافذة والبلاط بشكل طبيعي مع النوافذ الأخرى.
4) عندما تكون هناك نافذة مشروطة ، لا يمكن أن تعمل على نافذة الأم.
يتم استخدام رمز التنفيذ أعلاه في جميع إصدارات Delphi.