توصيات لإنشاء واجهات مستخدم في دلفي. ميزات العمل مع الواجهات في وصف واجهة دلفي دلفي

تحميل فايبر 23.01.2022
تحميل فايبر

واحدة من أعظم نقاط القوة في بيئة برمجة دلفي هي بنيتها المفتوحة ، والتي تسمح لدلفي بالسماح بنوع من البرمجة الوصفية ، مما يسمح لك "ببرمجة بيئة البرمجة". يرتقي هذا النهج بدلفي إلى مستوى جديد نوعيًا لأنظمة تطوير التطبيقات ويسمح لك بتضمين أدوات إضافية في هذا المنتج والتي تدعم تقريبًا جميع مراحل إنشاء أنظمة التطبيقات. يتم فتح مثل هذا النطاق الواسع من الاحتمالات بفضل مفهوم ما يسمى بالواجهات المفتوحة المطبقة في دلفي ، والتي هي الرابط بين IDE (بيئة التطوير المتكاملة) والأدوات الخارجية.

تركز هذه المقالة على واجهات دلفي المفتوحة وتوفر نظرة عامة على الميزات التي توفرها. تحدد دلفي ستة واجهات عامة: واجهة الأداة وواجهة التصميم وواجهة الخبراء وواجهة الملف وواجهة التحرير وواجهة التحكم في الإصدار. من غير المحتمل أن نتمكن في إطار هذه المقالة من تغطية بالتفصيل وتوضيح إمكانيات كل منها. ستساعدك النصوص المصدرية لدلفي على فهم القضايا قيد النظر بشكل أكثر شمولاً ، حيث أن المطورين قدموا لهم تعليقات مفصلة. إقرارات الفئة التي تمثل واجهات عامة موجودة في الوحدات النمطية المقابلة في دليل ... \ Delphi \ Source \ ToolsAPI. توفر واجهة التصميم (الوحدة النمطية DsgnIntf.pas) وسيلة لإنشاء برامج تحرير الخصائص ومحررات المكونات.

تعد محررات الخصائص والمكونات موضوعًا يستحق مناقشة منفصلة ، لذلك نتذكر فقط أن محرر الخصائص يتحكم في سلوك Object Inspector عندما تحاول تغيير قيمة الخاصية المقابلة ، ويتم تنشيط محرر المكون عندما تقوم بمضاعفة- انقر بزر الفأرة الأيسر على صورة المكون الموجود في النموذج. تم تصميم واجهة التحكم في الإصدار (الوحدة النمطية VCSIntf.pas) لإنشاء أنظمة التحكم في الإصدار. بدءًا من الإصدار 2.0 ، تدعم Delphi نظام التحكم في الإصدار المتكامل Intersolv PVCS ، لذلك في معظم الحالات ، ليس من الضروري تطوير نظامك الخاص. لهذا السبب ، سنحذف أيضًا اعتبار واجهة التحكم في الإصدار. تسمح لك واجهة الملف (الوحدة النمطية FileIntf.pas) بإعادة تعريف نظام ملفات العمل الخاص بـ IDE ، مما يجعل من الممكن اختيار طريقتك الخاصة لتخزين الملفات (في حقول المذكرة على خادم قاعدة البيانات ، على سبيل المثال). توفر واجهة التحرير (الوحدة النمطية EditIntf.pas) الوصول إلى المخزن المؤقت للنص المصدر ، والذي يسمح لك بتحليل وإنشاء التعليمات البرمجية وتحديد موضع المؤشر وتغييره في نافذة محرر التعليمات البرمجية والتحكم في تمييز بناء جملة النص المصدر.

توفر الفئات الخاصة واجهات للمكونات الموضوعة في النموذج (تحديد نوع المكون ، والحصول على مراجع للمكونات الرئيسية والتابعة ، والوصول إلى الخصائص ، وتمرير التركيز ، والحذف ، وما إلى ذلك) ، والنموذج نفسه ، وملف موارد المشروع. تتيح لك واجهة التحرير أيضًا تحديد ما يسمى بإخطارات الوحدة النمطية التي تحدد الاستجابة للأحداث مثل تغيير رمز المصدر للوحدة النمطية أو تعديل النموذج أو إعادة تسمية المكون أو حفظ الوحدة النمطية أو إعادة تسميتها أو حذفها أو تغيير مورد المشروع ملف ، وما إلى ذلك ، توفر واجهة الأداة (module ToolIntf. pas) للمطورين وسيلة للحصول على معلومات عامة حول حالة IDE وتنفيذ إجراءات مثل فتح وحفظ وإغلاق المشاريع والملفات الفردية ، وإنشاء وحدة نمطية ، والحصول على معلومات حول المشروع الحالي (عدد الوحدات النمطية والنماذج ، وأسمائها ، وما إلى ذلك) ، وتسجيل نظام الملفات ، وتنظيم الواجهات للوحدات النمطية الفردية ، إلخ. بالإضافة إلى تنبيهات الوحدة النمطية ، تحدد واجهة الأداة تنبيهات الوظائف الإضافية التي تخطر بأحداث مثل فتح / إغلاق الملفات والمشاريع ، وتحميل ملف سطح مكتب المشروع وحفظه ، وإضافة / استبعاد وحدات المشروع ، وتثبيت / إلغاء تثبيت الحزم ، وتجميع مشروع ، وعلى عكس التنبيهات المعيارية ، تسمح لك إشعارات الوظائف الإضافية بإلغاء تنفيذ بعض الأحداث.

بالإضافة إلى ذلك ، توفر واجهة الأداة وسيلة للوصول إلى القائمة الرئيسية لـ Delphi IDE ، مما يسمح لك بتضمين عناصر إضافية فيها. واجهة الخبراء (الوحدة النمطية ExptIntf.pas) هي الأساس لإنشاء خبراء - وحدات برمجية مدمجة في IDE من أجل توسيع وظائفها. مثال على الخبير هو معالج نموذج قاعدة بيانات دلفي ، والذي يقوم بإنشاء نموذج لعرض وتعديل محتويات جدول قاعدة البيانات. بعد تحديد فئة الخبراء ، نحتاج إلى التأكد من أن دلفي "تتعلم" عن خبيرنا. للقيام بذلك ، يجب تسجيله عن طريق استدعاء إجراء RegisterLibraryExpert ، وتمريره مثيلاً لفئة الخبير كمعامل. كتوضيح ، دعنا ننشئ خبيرًا بسيطًا في النمط القياسي ، والذي ، عند تحديد عنصر قائمة دلفي المقابل ، يعرض رسالة تفيد بأنه قيد التشغيل. كما ترى من الجدول أعلاه ، يتطلب نمط esStandard ستة طرق ليتم تجاوزها:

لكي يتم "تنشيط" الخبير ، يجب عليك تحديد عنصر القائمة مكون / تثبيت مكون ... ، حدد الوحدة التي تحتوي على الخبير (في حالتنا exmpl_01.pas) في مربع الحوار "استعراض" ، انقر فوق "موافق" ، وبعد التجميع الحزمة dclusr30.dpk في قائمة دلفي الرئيسية في قسم المساعدة ، يجب أن يظهر عنصر Simple Expert 1 ، عند تحديده ، تظهر الرسالة الإعلامية "Standard Expert بدأ!" لماذا تضع دلفي عنصر قائمة الخبير في قسم المساعدة يبقى لغزا. إذا كنت لا تحب حقيقة أن عنصر القائمة يظهر في أي مكان في دلفي ، وليس في المكان الذي تريده ، فإن الخيار التالي ممكن: إنشاء خبير في نمط الوظيفة الإضافية ، مما يلغي الإنشاء التلقائي لعنصر القائمة ، و أضف عنصر القائمة "يدويًا" باستخدام واجهة الأداة. سيسمح لك ذلك بتعيين موقع العنصر الجديد في القائمة الرئيسية بطريقة عشوائية.

لإضافة عنصر قائمة ، يتم استخدام فئة TIToolServices - أساس واجهة الأداة - وفئات TIMainMenuIntf و TIMenuItemIntf التي تنفذ واجهات لقائمة IDE الرئيسية وعناصرها. يتم إنشاء مثيل ToolServices لفئة TIToolServices بواسطة IDE نفسه عند تهيئته. لاحظ أن المطور مسئول عن تحرير الواجهات لقائمة دلفي الرئيسية وعناصرها. على طول الطريق ، دعنا نعقد قليلاً الحمل الوظيفي لـ Expert Advisor: عند تنشيط عنصر القائمة الخاص به ، سيصدر معلومات حول اسم المشروع المفتوح حاليًا في البيئة: كمعلمات ، يتم تمرير نص عنصر القائمة الجديد ، ومعرفه ، ومعرف العنصر الذي يتم إدخال العنصر الجديد قبله ، والتمثيل الرمزي للمفتاح ، والذي يمكن استخدامه مع مفتاح Ctrl للوصول بسرعة إلى عنصر جديد ومعالج الأحداث المطابق لاختيار العنصر الجديد. لقد أضفنا عنصر قائمة جديدًا إلى قسم العرض قبل عنصر الساعات.

الآن دعنا نتعرف على المخطرين. دعنا نحدد إشعار الوظيفة الإضافية الذي يتتبع وقت إغلاق / فتح المشاريع وضبط الحقل الذي يخزن اسم المشروع النشط وفقًا لذلك (نحذف تنفيذ الأساليب التي لم تتغير مقارنة بالمثال السابق للإيجاز): للتنفيذ المخطر ، قمنا بتعريف فئة TAddInNotifier ، والتي هي سليل TIAddInNotifier وتجاوز FileNotification. سوف يستدعي IDE هذه الطريقة في كل مرة يحدث فيها حدث يمكن لمُعلم الوظيفة الإضافية الاستجابة له (يُشار إلى كل حدث من هذا القبيل بواسطة ثابت نوع TFileNotification المقابل). يخدم حقل الخبير في فئة TAddInNotifier للتغذية الراجعة مع أحد الخبراء (طريقة TAddInNotifier.FileNotification). في مدمر الخبير ، يكون تسجيل المخطر غير مسجل ويتم إتلاف المخطر. الآن دعنا نوضح استخدام أجهزة الإخطار المعيارية. دعنا ننشئ خبيرًا إضافيًا يصدر رسائل حول كل إجراء لحفظ ملف مشروع (للإيجاز ، لم يتم تقديم تنفيذ الأساليب التي نعرفها بالفعل): في هذا المثال ، يراقب خبير الوظيفة الإضافية الأحداث المقابلة للافتتاح / إغلاق المشاريع.

في كل مرة يتم فيها فتح مشروع ، يتم تسجيل مُخطر الوحدة المقابلة لملف المشروع. فيما يتعلق بالتنفيذ ، تتشابه المذكرات المعيارية مع التنبيهات الإضافية: نحن نحدد فئة TModuleNotifier التي تنحدر من TIModuleNotifier وتجاوز أساليب Notify و ComponentRenamed الخاصة بها. يستدعي IDE أسلوب الإعلام عند حدوث أحداث معينة متعلقة بهذه الوحدة النمطية ؛ داخل هذه الطريقة ، يتم تحديد رد الفعل على حدث معين. يتم استدعاء الأسلوب ComponentRenamed عندما يتغير اسم المكون الموجود في نموذج الوحدة النمطية. يرجى ملاحظة أننا لا نستخدم هذه الطريقة ، ولكن يجب تجاوزها ، وإلا عندما يتغير اسم المكون ، سيتم استدعاء الطريقة المجردة للفئة الأساسية ، مما يؤدي إلى عواقب غير متوقعة.

يعد تسجيل برنامج إشعار الوحدة النمطية أكثر تعقيدًا إلى حد ما من تسجيل وظيفة إضافية للمخطر: أولاً نحصل على واجهة الوحدة النمطية (TIModuleInterface) ثم نقوم بتسجيل المخطر باستخدام واجهة الوحدة النمطية. عند إغلاق المشروع ، لا يتم تسجيل مُخطر الوحدة النمطية (مرة أخرى باستخدام TIModuleInterface) ويتم إتلاف المخطر. في الختام ، سنوضح كيف يمكنك تحديد موضع المؤشر في نافذة محرر الكود. لنقم بإنشاء Expert Advisor والذي ، عند تحديد عنصر القائمة المناسب ، سيعرض رسالة تحتوي على اسم الملف النشط وموضع المؤشر فيه (يتم تقديم تنفيذ الأساليب الضرورية فقط لهذا المثال): لتحديد موضع المؤشر ، يجب أن نتلقى التسلسل التالي من الواجهات: واجهة الوحدة النمطية (TIModuleInterface)؛ واجهة محرر الكود (TIEditorInterface) ؛ واجهة عرض الوحدة النمطية في نافذة المحرر (TIEditView).

إذا كان الملف النشط الذي يحتوي على نص المصدر (* .pas) نشطًا عند تحديد عنصر قائمة الخبير ، فسيتم عرض رسالة تحتوي على اسم الملف النشط والموضع الحالي للمؤشر فيه. إذا لم يكن الملف النشط ملف pas ، فلن يتم إصدار أي رسالة. يتم استخدام طريقة GetCurrentFile لفئة TIToolServices للحصول على اسم الملف النشط. بهذا نختتم مناقشتنا لطرق استخدام الواجهات العامة. يحتوي القرص المضغوط على شفرة المصدر لجميع الأمثلة المقدمة. يحتوي القرص المضغوط أيضًا على مثال أكثر تعقيدًا وتمديدًا يحتوي على خبير الوظيفة الإضافية الذي يسمح للمستخدم بوضع إشارة مرجعية على التعليمات البرمجية المصدر لوحدات دلفي النمطية. يوجد دليل سريع لتثبيت واستخدام Bookmark Expert في ملف bkmrks97.htm. لذلك ، في هذه المقالة ، تتم مناقشة الواجهات العامة بشكل عام ويتم تقديم أمثلة على استخدامها. مرة أخرى ، بفضل توفر أكواد المصدر للواجهات المفتوحة ، يمكنك بسهولة فهم التفاصيل التي تهمك. نأمل أن تعطيك الإمكانيات المتنوعة التي توفرها الواجهات المفتوحة أكثر من فكرة جريئة ومفيدة.

فقط من أجل النتائج

التقيد الصارم بالمواعيد النهائية

الشفافية

تنفيذ المشروع

الدعم الفني كهدية

البرمجة والتحسينات والمشاورات على 1C

كيف نعمل

1. نناقش المشكلة عن طريق الهاتف. إذا كان لديك وصول عن بعد - اعرضه على شاشة جهاز الكمبيوتر الخاص بك.

2. نقيم العمل بالروبل إذا كان المشروع كبيرًا ، إن لم يكن - العدد التقريبي للساعات.

3. ننجز المهمة.

4. تقبل العمل في برنامجك ، فإذا كانت هناك أوجه قصور نقوم بتصحيحها.

5. نحن نصدر فاتورة ، عليك الدفع.

تكلفة العمل

1. تنقسم جميع الأعمال إلى 3 فئات: الاستشارة ، وتحديث التكوين النموذجي ، وتطوير أو برمجة تقرير جديد ، والمعالجة ، والأزرار ، وما إلى ذلك.

3. للعمل الذي يزيد عن 10 ساعات ، يتم إعداد مهمة فنية مسبقًا مع وصف وتكلفة العمل. يبدأ العمل بعد الموافقة على المواصفات معك.

دعم فني

1. إذا وجدت أي أخطاء في أعمال تم قبولها مسبقًا ، في غضون 3 أشهر ، نقوم بتصحيحها مجانًا.

2. بالنسبة للعملاء المنتظمين ، نقوم بإصلاح أي قصور في عملنا مجانًا خلال عام.

برامج لإدارة عملك.

شراء 1C: المؤسسة

نحن الموزع الرسمي لـ 1C ، يمكنك شراء العديد من منتجات البرامج والتراخيص منا. بالإضافة إلى شراء "صندوق" ، سنساعدك في إعداد البرنامج والاستشارة وإجراء الإعدادات الأساسية.

  • محاسبة
  • أتمتة المتجر
  • بالجملة
  • يتم تضمين المساعدة في التثبيت والإعداد الأولي في الحزمة!
  • صقل التكوينات حسب احتياجات العميل ، وتطوير وحدات جديدة في حالة عدم وجود الوظائف الضرورية في التكوين القياسي.
1 ج المحاسبة 1 ج: إدارة التجارة 1C: البيع بالتجزئة 1 ج: إدارة الرواتب والموارد البشرية
من 3300 فرك. من 6700 فرك. من 3300 فرك. من 7400 فرك.

توفير خادم.

خادم الإعداد الفوري + 1C.

لا خادم؟ لا يهم ، سنختار خادمًا وننشئه بسرعة في "السحابة". مقابل رسوم رمزية ، تحصل على حل موثوق للغاية.

  • التوفر 24 \ 7
  • لا حاجة للاحتفاظ بمسؤول النظام الخاص بك (ستغطي المدخرات تكلفة الخادم الخاص بك).
  • الإعداد والتثبيت السريع لـ 1C على الخادم ، في غضون 3 أيام سيكون لديك بالفعل نظام يعمل بشكل كامل.
  • في أي وقت ، يمكنك الانتقال إلى خادم محلي إذا كان الحل لا يناسبك.

الرسائل القصيرة من 1C الخاص بك

هل تريد أن يتعرف العملاء على العروض الترويجية والخصومات في الوقت المناسب؟ العملاء لا يعودون؟ قم بإعداد إرسال الرسائل القصيرة مباشرة من 1C!

ستكون شركتنا قادرة على إعداد إرسال الرسائل القصيرة بسرعة إلى عملائك مباشرة من 1C. أمثلة على الأحداث التي يمكن أتمتتها:

  • الامتنان للشراء وتراكم المكافآت مباشرة بعد عملية الشراء التالية.
  • تراكم المكافآت على البطاقة كهدية لعيد ميلاد / يوم آخر مهم أو يوم عطلة.
  • إشعار المستودع.
  • انتهاء صلاحية قسيمة الهدية.
  • إخطار باستلام الدفعة المسبقة وحجز البضائع.
  • العنوان مع الاتجاهات إلى المتجر / المكتب ، وأرقام الهواتف.
  • إلخ.

يمكن أن يتم الإعداد في 1C بواسطة متخصصينا أو موظفينا. يمكنك التعرف على التعريفات على صفحة تعريفات الرسائل القصيرة.

  • ضمان تسليم الرسائل القصيرة ، يتم سحب الأموال فقط للرسائل القصيرة التي تم تسليمها.
  • فاتورة منفصلة لكل رسالة قصيرة.
  • تجديد الرصيد بطرق مختلفة.
  • عرض محفوظات جميع الرسائل القصيرة المرسلة في أي وقت.
  • اسم المرسل بدلاً من الرقم الرقمي على هاتف المستلم.

لدي مشكلة في استخدام فئة دلفي من كود C ++. عرض دلفي dll الذي يقوم بتصدير دالة تقوم بإرجاع كائن.
يبدو كود Delphi Dll الخاص بي كما يلي:

مكتبة DelphiTest ؛ // يستخدم الجزء .... اكتب IMyObject = إجراء الواجهة DoThis (n: Integer) ؛ وظيفة DoThat: PWideChar ؛ نهاية؛ TMyObject = فئة (TInterfacedObject ، IMyObject) إجراء DoThis (ن: عدد صحيح) ؛ وظيفة DoThat: PChar ؛ نهاية؛ // تنفيذ TMyObject ، انتقل هنا ... إجراء TMyObject.DoThis (ن: عدد صحيح) ؛ ابدأ showmessage ("أنت تستدعي طريقة DoThis بـ" + intToStr (n) + "المعلمة") ؛ نهاية؛ وظيفة TMyObject.DoThat: PChar ؛ ابدأ showmessage ("أنت تستدعي وظيفة DoThat") ؛ النتيجة: = Pchar ("Hello im Dothat") ؛ نهاية؛

// تصدير وظيفة DLL:

الدالة CreateMyObject: IMyObject ؛ stdcall تصدير [عامة] var txt: TextFile ؛ ابدأ AssignFile (txt، "C: \ log.log") ؛ إعادة تعيين (النص) ؛ Writeln (txt، "hello") ؛ النتيجة: = TMyObject.Create ؛ نهاية؛ تصدير CreateMyObject ؛

في مشروع C ++ الخاص بي ، أعلنت عن واجهة IMyObject مثل هذا:

فئة IMyObject (عامة: IMyObject () ؛ افتراضي ~ IMyObject () ؛ الفراغ الظاهري DoThis (int n) = 0 ؛ حرف ظاهري * DoThat () = 0 ؛) ؛

ووظيفتي الرئيسية هي كما يلي:

Typedef IMyObject * (__stdcall * CreateFn) () ؛ int main () (HMODULE hLib ؛ hLib = LoadLibrary (L "DelphiTest.dll") ؛ تأكيد (hLib! = NULL) ؛ // pass !! CreateFn pfnCreate ؛ pfnCreate = (CreateFn) GetProcAddress ((HINSTANCE) hLib ، "CreateMyObject ") ؛ إذا (pfnCreate == NULL) (DWORD errc = GetLastError () ؛ printf ("٪ u \ n "، errc) ؛ // تحصل على الخطأ 127) وإلا (printf (" نجاح التحميل \ n ") ؛) IMyObject * objptr = pfnCreate ()؛ objptr-> DoThis (5)؛ FreeLibrary (hLib)؛ int in؛ scanf_s ("٪ i"، & in)؛ return 0؛)

في هذا المثال ، حصلت على خطأ في وقت التشغيل عندما أحاول الوصول إلى الوظيفة المصدرة. أخطاء الخط:
IMyObject * objptr = pfnCreate () ،

هل يمكن أن تخبرني ما هو الخطأ في نموذجي.
وإذا أمكن أي مثال عملي للوصول إلى فئة دلفي (في DLL) من كود C ++.

المحلول

المشكلة الأولى هي استدعاء طريقة الاصطلاح. تستخدم واجهة دلفي السجل وهو اصطلاح استدعاء خاص بدلفي. باستخدام stdcall ، على سبيل المثال ، لطرق الواجهة.

المشكلة التالية في C ++. يجب أن تنبثق واجهة C ++ من IUnknown. أيضًا ، يجب ألا تعلن عن مُنشئ أو مُدمِّر.

بخلاف ذلك ، تصدر شفرة دلفي الخاصة بك PWideChar الذي لا يتم تعيينه إلى char *.

إذا نظرنا إلى أبعد من ذلك ، فإن إرجاع PChar يعمل بشكل رائع هنا لأن تنفيذك يعيد حرفًا. ولكن قد ترغب التعليمات البرمجية الأكثر جدية في استخدام سلسلة مخصصة ديناميكيًا ، وعند هذه النقطة يكون تصميمك معيبًا.

لاحظ أنه يجب أن تكون مسؤولاً رفيع المستوى لإنشاء ملف في جذر محرك أقراص النظام. لذا فهذه نقطة أخرى محتملة للفشل.

أتوقع وجود أخطاء أخرى ، ولكن هذا كل ما وجدته حتى الآن.

تستند هذه المقالة إلى أسئلة في المنتديات: "كيف يمكنني إرجاع سلسلة من DLL؟" ، "كيف يمكنني تمرير مجموعة من السجلات وإعادتها؟" ، "كيف يمكنني تمرير نموذج إلى DLL؟".

حتى لا تقضي نصف حياتك في اكتشاف ذلك - في هذه المقالة سأقوم بإحضار كل شيء على طبق من الفضة.

تم التطرق بالفعل إلى مواضيع هذه المقالة ، بدرجات متفاوتة ، أكثر من مرة في هذه المدونة ، ولكن في هذه المقالة تم جمعها في كومة ، يتم تقديم التبريرات. باختصار ، يمكن إلقاء رابط لهذه المقالة على أولئك الذين يطورون DLL.

ملاحظة مهمة: يجب قراءة المقال على التوالي. يتم توفير أمثلة التعليمات البرمجية فقط كـ أمثلة، في كل خطوة (نقطة) من المقال ، تتم إضافة رمز الأمثلة بتفاصيل جديدة. على سبيل المثال ، في بداية المقال لا توجد معالجة للخطأ ، تتم الإشارة إلى الأساليب "الكلاسيكية" (مثل استخدام GetLastError ، واصطلاحات sdtcall ، وما إلى ذلك) ، والتي يتم استبدالها بأساليب أكثر ملاءمة في سياق المقالة. يتم ذلك لأن التصميمات "الجديدة" ("غير العادية") لا تثير تساؤلات. خلاف ذلك ، مع كل مثال ، سيتعين على المرء إدراج ملاحظة عن النموذج: "تمت مناقشة هذا في تلك الفقرة أدناه ، ولكن هذا - في هذا المثال هنا." على أي حال ، يوجد في نهاية المقال رابط إلى رمز جاهز مكتوب مع مراعاة كل ما يقال في المقالة. يمكنك فقط أخذه واستخدامه. ويشرح المقال لماذا ولماذا. إذا لم تكن مهتمًا بـ "لماذا ولماذا" - انتقل إلى نهاية الاستنتاج ورابط لتنزيل المثال.



نوصي بالقراءة

قمة