SpaceVIL هو إطار واجهة المستخدم الرسومية عبر منصة لتطوير .Net Core و .Net Standard و JVM

في هذه المقالة سأحاول التحدث عن إطار عمل SpaceVIL (مساحة تخطيط العناصر المرئية) ، والذي يستخدم لبناء واجهات المستخدم الرسومية على منصات .Net / .Net Core و JVM.


SpaceVIL هو إطار متعدد المنصات ومتعدد اللغات ، وهو يعتمد على تقنية رسومات OpenGL ، ومكتبة GLFW هي المسؤولة عن إنشاء النوافذ. باستخدام هذا الإطار ، يمكنك العمل وإنشاء تطبيقات العميل الرسومية في أنظمة تشغيل Linux و Mac OS X و Windows. بالنسبة إلى مبرمجي C # ، يكون هذا صحيحًا بشكل خاص في الوقت الحالي ، نظرًا لأن Microsoft لن تنقل WPF إلى أنظمة تشغيل أخرى وأن Avalonia هو التناظرية الوحيدة الممكنة. خصوصية SpaceVIL في هذه الحالة بالذات هي تعدد اللغات ، أي في الوقت الحالي يمكن استخدام .Net Core بالاقتران مع لغات البرمجة التالية: C # ، VisualBasic. يمكن استخدام إطار JVM بالاقتران مع لغات Java و Scala. وهذا يعني أنه يمكن استخدام SpaceVIL مع أي من هذه اللغات وسوف يظهر الرمز الناتج كما هو ، لذلك عند التبديل إلى لغة أخرى ، لن تضطر إلى إعادة تعلمها مرة أخرى.


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


تم تطوير SpaceVIL من نقطة الصفر وهذا هو السبب في أن الإطار له مبادئه الخاصة التي تميزه عن نظائره.


  • مستخدم SpaceVIL لديه سيطرة كاملة على ما يحدث.
  • أي تطبيق مكتوب في SpaceVIL سوف يظهر بنفس الشكل على جميع المنصات. لا توجد مطبات. يمكنك استخدام أي إصدار من SpaceVIL (.Net / JVM و Mac OS X و Linux و Windows) ، وستظل النتيجة والمظهر دائمًا كما هو.
  • إصدار SpaceVIL لـ JVM مماثل في استخدام إصدار SpaceVIL لـ .Net
  • يوفر SpaceVIL فرصًا للتخصيص العميق لعنصر ما ، حيث أن جميع الكائنات التفاعلية عبارة عن حاويات للكائنات التفاعلية الأخرى.
  • إطار العمل مرن جدًا وسهل الاستخدام ، نظرًا لوجود عدد قليل من القواعد الأساسية الصارمة فيه ، والشيء الوحيد الذي تحتاج إلى فهمه قبل البدء في العمل هو ما تعنيه إعدادات Padding و Margin و Alignment (وأي شخص قام بإنشاء واجهات بسيطة يعرفها ، في WPF ، Android Studio أو كتب أنماطًا في CSS).
  • لن يطلب منك SpaceVIL منك القيام بأي دراسة متعمقة عن الدواخل الداخلية لها ، وسوف تفعل ما تكتبه بالضبط. جميع العناصر تطيع القواعد العامة ، نهج واحد سوف تعمل على جميع العناصر. بعد أن تذكرت الأساس ، سيكون من الممكن التنبؤ بتكوين العناصر وطرق تصميمها.
  • الإطار خفيف الوزن للغاية ، أقل من ميغابايت وكلها في ملف واحد.

الاحتمالات


الآن لنرى ما هو الإطار الحالي للإصدار الحالي.


  • 54 عنصرًا متاحًا للاستخدام ، منها 10 حاويات متخصصة و 6 عناصر أولية (عناصر غير تفاعلية) و 38 عنصرًا تفاعليًا لأغراض متعددة.
  • بناءً على كل هذه العناصر ، إلى جانب تنفيذ واجهات خاصة ، يمكنك إنشاء عناصرك الخاصة بأي تعقيد.
  • هناك تصميم للعناصر ، وهناك خيارات لإنشاء سمات نمط كامل أو تغيير / استبدال نمط أي عنصر قياسي في الإطار. حتى الآن ، يوجد موضوع واحد فقط في SpaceVIL ويتم تثبيته افتراضيًا.
  • هناك نظام الدول. يمكن تعيين حالة مرئية لكل عنصر لإحدى طرق التأثير الخارجي: التمرير فوق العنصر والضغط على زر الماوس وإطلاق زر الماوس والتبديل والتركيز وإيقاف تشغيل العنصر.
  • هناك تصفية الحدث. يمكن لكل عنصر في التفاعل تصفية الأحداث التي تمر خلالها ، مما يسمح لحدث واحد بالمرور عبر العنصر ويتجاهله الآخر. في مثال سأقول عنه بمزيد من التفصيل.
  • نفذت نظاما من العناصر المستقلة العائمة.
  • تم تطبيق نظام مربعات الحوار وعناصر الحوار.
  • تنفيذ التقديم المستقل. تحتوي كل نافذة على دفقين - أحدهما يتحكم في العرض ، والآخر يؤدي مهام من الأحداث الواردة ، أي أن النافذة الآن تستمر دائمًا في العرض (ولا "تعلق") ، بغض النظر عن المهمة التي تم إطلاقها بعد الضغط على زر.

هيكل


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


حاويات


يتم تقديم أنواع الحاوية التالية في SpaceVIL:


  • حاوية شائعة (يتم وضع العناصر الموجودة داخل هذه الحاوية بسبب معلمات سياسة المحاذاة والحشو والهامش والحجم والحجم).
  • مكدسات رأسية وأفقية (سيتم ترتيب العناصر المضافة إلى هذه الحاوية بالترتيب دون الحاجة إلى ضبط المعلمات المطلوبة عند استخدام النوع السابق من الحاوية).
  • الشبكة - يتم إضافة عناصر إلى خلايا الشبكة ووضعها داخل الخلية الخاصة بهم.
  • قائمة (ListBox ، TreeView) ، حاوية قائمة على مكدس عمودي ، ولكن مع القدرة على التمرير لعرض العناصر التي لا تنسجم مع الحاوية.
  • فاصل (SplitArea) ، يمكن أن تكون الحاوية من نوعين - رأسيًا وأفقيًا ، تفصل منطقتين وتتحكم بشكل تفاعلي في حجم هذه المناطق.
  • حاوية مبوبة (TabView) ، تتحكم في رؤية الصفحة.
  • تقوم WrapGrid بوضع العناصر داخل خلايا ذات حجم معين ، في ملء المساحة الحرة وفقًا للتوجيه مع إمكانية التمرير (المثال الأكثر وضوحًا هو Windows Explorer في وضع عرض الأيقونة).
  • وأخيرًا ، تعتبر الحاوية المجانية ، التي ربما تكون أندر الحاوية ، منطقة لا حصر لها يمكنك إضافة أي عناصر ذات حجم ثابت إليها ، ولكن من الأفضل استخدامها مع عنصر من النوع ResizableItem.

العناصر التفاعلية


عناصر من هذا النوع تقبل العديد من الدول ولها أحداث مختلفة. إذا كان الأمر أكثر بساطة ، فكل شيء يمكنك التفاعل به وهناك عناصر تفاعلية ، على سبيل المثال: زر ، مربع اختيار ، عنصر لإدخال النص ، وغيرها.


البدائيون


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


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


مثال على تطبيق بسيط باستخدام إطار SpaceVIL


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


دعنا ننتقل إلى وصف التطبيق. البرنامج عبارة عن محرر بطاقات للألعاب مثل "Dungeons and Dragons" ولديه اسم CharacterEditor. البرنامج يولد عشوائيا عددا محددا من الشخصيات المختلفة مع الأسماء والعمر والعرق والجنس والفئة والخصائص. يتم إعطاء المستخدم الفرصة لكتابة السيرة الذاتية وإعطاء المهارات الشخصية المتخصصة. نتيجة لذلك ، يمكنك حفظ بطاقة البطل كملف نصي. دعنا ننكب على تحليل الرمز. البرنامج مكتوب بلغة سي. عند استخدام Java ، سيكون الكود هو نفسه بشكل أساسي.


نتيجة لذلك ، حصلنا على مثل هذا التطبيق:



إنشاء نافذة التطبيق


في هذه المرحلة سنقوم بإنشاء نافذة. اسمحوا لي أن أذكرك بأن SpaceVIL يستخدم GLFW ، لذلك إذا كنت تكتب طلبًا لمنصة .Net ، فيجب نسخ مكتبة GLFW المترجمة بجوار الملف القابل للتنفيذ. يستخدم JVM مجمّع مكتبة GLFW (LWJGL) ، والذي يتضمن بالفعل GLFW مترجم.


بعد ذلك ، املأ منطقة العرض بالعناصر اللازمة ومنحها مظهرًا رائعًا. الخطوات الرئيسية لتحقيق ذلك هي كما يلي:


  • تهيئة SpaceVIL قبل استخدامه. في الوظيفة الرئيسية ، اكتب فقط:

if (!SpaceVIL.Common.CommonService.InitSpaceVILComponents()) return; 

  • الآن إنشاء نافذة. للقيام بذلك ، تحتاج إلى كتابة فئة نافذة ، وراثة من فئة SpaceVIL.ActiveWindow ، ووصف أسلوب InitWindow() وتعيينها مع العديد من المعلمات الأساسية ، مثل اسم النافذة ونص شريط العنوان والأبعاد. نتيجة لذلك ، حصلنا على رمز يشبه هذا:

 using System; using SpaceVIL; namespace CharacterEditor { internal class MainWindow : ActiveWindow { public override void InitWindow() { SetParameters("CharacterEditor", "CharacterEditor", 1000, 600); } } } 

  • يبقى فقط إنشاء مثيل لهذه الفئة والاتصال بها. للقيام بذلك ، نضيف الطريقة الرئيسية بسطر الكود التالي:

 MainWindow mw = new MainWindow(); mw.Show(); 

هذا كل شيء ، في هذه المرحلة يمكنك بدء التطبيق ومعرفة ما إذا كان كل شيء يعمل.


ملء مع العناصر


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


 public override void InitWindow() { SetParameters("CharacterEditor", "CharacterEditor", 1000, 600); //   Frame frame = new Frame(); // ,      frame ButtonCore btn = new ButtonCore("Button"); //    , //      . // frame     , //,   . frame.AddItem(btn); //  frame    AddItem(frame); } 

من المناسب إضافة frame إلى النافذة أولاً ، ثم إضافة زر إلى frame . قد يبدو أن القاعدة غير مريحة للغاية وسيتعين عليك التعرق عند إنشاء نافذة معقدة ، وهذا هو السبب في أن SpaceVIL يشجعك على إنشاء عناصر خاصة بك ، مما يبسط إضافة العناصر إلى حد كبير. سوف أشرح وأشرح إنشاء العناصر الخاصة بي بعد ذلك بقليل. دعنا نعود إلى التطبيق. هنا هي النافذة الناتجة:



الآن دعنا تحليل الكود:


MainWindow رمز ملخص العلامات
 internal ListBox ItemList = new ListBox(); //     internal TextArea ItemText = new TextArea(); //     internal ButtonCore BtnGenerate; //   internal ButtonCore BtnSave; //    internal SpinItem NumberCount; //    public override void InitWindow() { SetParameters("CharacterEditor", "CharacterEditor", 1000, 600); IsBorderHidden = true; //      IsCentered = true; //       //  TitleBar title = new TitleBar(nameof(CharacterEditor)); //     title.SetIcon( DefaultsService.GetDefaultImage(EmbeddedImage.User, EmbeddedImageSize.Size32x32), 20, 20); // ,       VerticalStack layout = ItemFactory.GetStandardLayout(title.GetHeight()); //  HorizontalStack toolbar = ItemFactory.GetToolbar(); //  VerticalSplitArea splitArea = ItemFactory.GetSplitArea(); //  BtnGenerate = ItemFactory.GetToolbarButton(); //  BtnSave = ItemFactory.GetToolbarButton(); //    NumberCount = ItemFactory.GetSpinItem(); //    ItemText.SetStyle(StyleFactory.GetTextAreaStyle()); //     AddItems(title, layout); layout.AddItems(toolbar, splitArea); toolbar.AddItems(BtnGenerate, BtnSave, ItemFactory.GetVerticalDivider(), NumberCount); splitArea.AssignLeftItem(ItemList); splitArea.AssignRightItem(ItemText); //    BtnGenerate.AddItem(ItemFactory.GetToolbarIcon( DefaultsService.GetDefaultImage(EmbeddedImage.Refresh, EmbeddedImageSize.Size32x32))); BtnSave.AddItem(ItemFactory.GetToolbarIcon( DefaultsService.GetDefaultImage(EmbeddedImage.Diskette, EmbeddedImageSize.Size32x32))); } 

في فئة ItemFactory قمت بوصف مظهر العناصر وتخطيطها. على سبيل المثال ، يبدو أسلوب ItemFactory.GetToolbarButton() كما يلي:


 internal static ButtonCore GetToolbarButton() { ButtonCore btn = new ButtonCore(); //     btn.SetBackground(55, 55, 55); // btn.SetHeightPolicy(SizePolicy.Expand); //       btn.SetWidth(30); //  btn.SetPadding(5, 5, 5, 5); //       // ,           btn.AddItemState(ItemStateType.Hovered, new ItemState(Color.FromArgb(30, 255, 255, 255))); //  ItemState   return btn; } 

يتم وصف العناصر المتبقية بالمثل.


إنشاء وتطبيق الأنماط


كما لاحظت ، قمت بتطبيق نمط على عنصر ItemText . لذلك دعونا نلقي نظرة على كيفية إنشاء أنماط ، أولاً ، إلقاء نظرة على رمز النمط:


 Style style = Style.GetTextAreaStyle(); //       style.Background = Color.Transparent; //   Style textedit = style.GetInnerStyle("textedit"); //     textedit.Foreground = Color.LightGray; //   Style cursor = textedit.GetInnerStyle("cursor"); //     cursor.Background = Color.FromArgb(0, 162, 232);//   

كما ترون ، أخذت نمطًا جاهزًا من فئة SpaceVIL.Style لهذا العنصر وقمت بتغييره قليلاً ، مع تصحيح الألوان. يمكن أن يحتوي كل نمط على العديد من الأنماط الداخلية لتصميم كل عنصر مركب مكون. على سبيل المثال ، يتكون عنصر CheckBox من حاوية ومؤشر ونص ، لذلك يحتوي نمطه على أنماط داخلية للمؤشر ("المؤشر") والنص ("textline").


تغطي فئة Style جميع الخصائص المرئية للعناصر ، بالإضافة إلى ذلك ، باستخدام النمط ، يمكنك تغيير شكل عنصر بشكل تفاعلي ، على سبيل المثال ، من القطع الناقص إلى المستطيل والعكس. لتطبيق نمط ، تحتاج إلى استدعاء الأسلوب SetStyle(Style style) على العنصر ، كما هو موضح أعلاه أعلاه:


 ItemText.SetStyle(StyleFactory.GetTextAreaStyle()); 

إنشاء البند الخاص بك


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


لجعله أكثر إثارة للاهتمام ، نحدد تكوين العنصر أكثر تعقيدا:


  • رمز الحرف الذي يشير لونه إلى الانتماء إلى سباق خيالي.
  • الاسم واللقب وسباق الشخصية في شكل نص.
  • حرف مساعدة سريعة زر (اللازمة لإظهار أحداث التصفية).
  • زر لحذف الشخصية ، إذا كان لا يناسبنا.

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


دعنا ننتقل إلى تحليل رمز العنصر النهائي:


رمز العنصر CharacterCard
 using System; using System.Drawing; using SpaceVIL; using SpaceVIL.Core; using SpaceVIL.Decorations; using SpaceVIL.Common; namespace CharacterEditor { //   SpaceVIL.Prototype internal class CharacterCard : Prototype { private Label _name; private CharacterInfo _characterInfo = null; //      CharacterInfo, //       internal CharacterCard(CharacterInfo info) { //      //        SetSizePolicy(SizePolicy.Expand, SizePolicy.Fixed); SetHeight(30); //   SetBackground(60, 60, 60); //  SetPadding(10, 0, 5, 0); //    SetMargin(2, 1, 2, 1); //   AddItemState(ItemStateType.Hovered, new ItemState(Color.FromArgb(30, 255, 255, 255))); _characterInfo = info; //      //      Label _name = new Label(info.Name + " the " + info.Race); } public override void InitElements() { //  ImageItem _race = new ImageItem(DefaultsService.GetDefaultImage( EmbeddedImage.User, EmbeddedImageSize.Size32x32), false); _race.KeepAspectRatio(true); //   // ImageItem   _race.SetWidthPolicy(SizePolicy.Fixed); _race.SetWidth(20); // ImageItem // ImageItem       _race.SetAlignment(ItemAlignment.Left, ItemAlignment.VCenter); //  ()     switch (_characterInfo.Race) { case CharacterRace.Human: //   _race.SetColorOverlay(Color.FromArgb(0, 162, 232)); break; case CharacterRace.Elf: //   _race.SetColorOverlay(Color.FromArgb(35, 201, 109)); break; case CharacterRace.Dwarf: //   _race.SetColorOverlay(Color.FromArgb(255, 127, 39)); break; } // Label _name _name.SetMargin(30, 0, 30, 0); //    //    ButtonCore infoBtn = new ButtonCore("?"); infoBtn.SetBackground(Color.FromArgb(255, 40, 40, 40)); infoBtn.SetWidth(20); infoBtn.SetSizePolicy(SizePolicy.Fixed, SizePolicy.Expand); infoBtn.SetFontStyle(FontStyle.Bold); infoBtn.SetForeground(210, 210, 210); infoBtn.SetAlignment(ItemAlignment.VCenter, ItemAlignment.Right); infoBtn.SetMargin(0, 0, 20, 0); infoBtn.AddItemState(ItemStateType.Hovered, new ItemState(Color.FromArgb(0, 140, 210))); //   // info        infoBtn.SetPassEvents(false); //   //     info //  hover    infoBtn.EventMouseHover += (sender, args) => { SetMouseHover(true); }; //     info   //      infoBtn.EventMouseClick += (sender, args) => { //  ImageItem ImageItem race = new ImageItem(DefaultsService.GetDefaultImage( EmbeddedImage.User, EmbeddedImageSize.Size32x32), false); race.SetSizePolicy(SizePolicy.Fixed, SizePolicy.Fixed); race.SetSize(32, 32); race.SetAlignment(ItemAlignment.Left, ItemAlignment.Top); race.SetColorOverlay(_race.GetColorOverlay()); //  PopUpMessage popUpInfo = new PopUpMessage( _characterInfo.Name + "\n" + "Age: " + _characterInfo.Age + "\n" + "Sex: " + _characterInfo.Sex + "\n" + "Race: " + _characterInfo.Race + "\n" + "Class: " + _characterInfo.Class); //    3  popUpInfo.SetTimeOut(3000); popUpInfo.SetHeight(200); //   //  ,    //    popUpInfo.Show(GetHandler()); //      popUpInfo.AddItem(race); }; //   ButtonCore removeBtn = new ButtonCore(); removeBtn.SetBackground(Color.FromArgb(255, 40, 40, 40)); removeBtn.SetSizePolicy(SizePolicy.Fixed, SizePolicy.Fixed); removeBtn.SetSize(10, 10); removeBtn.SetAlignment(ItemAlignment.VCenter, ItemAlignment.Right); removeBtn.SetCustomFigure(new CustomFigure(false, GraphicsMathService.GetCross(10, 10, 2, 45))); removeBtn.AddItemState(ItemStateType.Hovered, new ItemState(Color.FromArgb(200, 95, 97))); //       removeBtn removeBtn.EventMouseClick += (sender, args) => { RemoveSelf(); //  }; //      CharacterCard AddItems(_race, _name, infoBtn, removeBtn); } internal void RemoveSelf() { //         GetParent().RemoveItem(this); } public override String ToString() { return _characterInfo.ToString(); } } } 

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


معالجة الحدث والتصفية


في المثال السابق ، تم وصف نوعين من الأحداث: MouseHover و MouseClick. لا يوجد سوى 11 حدثًا أساسيًا في الوقت الحالي ، إليك القائمة:


  • EventMouseHover
  • EventMouseLeave
  • EventMouseClick
  • EventMouseDoubleClick
  • EventMousePress
  • EventMouseDrag
  • EventScrollUp
  • EventScrollDown
  • EventKeyPress
  • EventKeyRelease
  • EventTextInput

تحتوي العناصر المعقدة على أحداث فريدة خاصة بها ، ولكن الأحداث المذكورة أعلاه متاحة (مع الحجز) للجميع.


بناء الجملة لمعالجة الأحداث تافه ويبدو كما يلي:


 // C# item.EventMouseClick += (sender, args) => { // - }; 

 // Java item.eventMouseClick.add((sender, args) -> { // - }); 

الآن دعنا ننتقل إلى تصفية الأحداث. بشكل افتراضي ، تمر الأحداث عبر هرم العناصر. في المثال الخاص بنا ، يتلقى الزر infoBtn حدث النقر فوق الزر الموجود على زر infoBtn ، ثم سيتلقى هذا الحدث عنصر CharacterCard ، ثم ListBox الذي سيتم تحديد موقعه ، ثم SplitArea ، و VerticalStack ، SplitArea في النهاية إلى عنصر Wontainer الأساسي.


في كل عنصر ، يمكنك التعامل مع EventMouseClick وسيتم EventMouseClick جميع هذه الإجراءات بالترتيب المحدد ، ولكن ماذا لو عند النقر على أي عنصر لا نريد أن يستمر هذا الحدث على طول السلسلة؟ لهذا ، هناك فقط تصفية الحدث. دعنا نظهر بشكل أكثر وضوحا ، على سبيل المثال ، على عنصر CharacterCard . تخيل أن CharacterCard يصف EventMouseClick ، الذي يدرج معلومات من CharacterInfo المرتبط في حقل نص لتحرير حرف. سيكون هذا السلوك منطقيًا - نضغط على العنصر ونرى كل معلمات الشخصية. بعد ذلك ، نقوم بتحرير الشخصية ، باختراع سيرة ومهارات ، أو تغيير الخصائص. في مرحلة ما ، أردنا أن نرى معلومات مختصرة عن شخصية أخرى تم إنشاؤها من القائمة وانقر على زر infoBtn. إذا لم نقوم بتصفية الأحداث ، فبعد استدعاء تلميح الأدوات ، سيتم تنفيذ EventMouseClick على عنصر CharacterCard نفسه ، والذي ، كما نتذكر ، يدرج نصًا في حقل تحرير الأحرف ، مما سيؤدي إلى فقد التغييرات إذا لم نحفظ النتائج ، وسوف يكون سلوك التطبيق نفسه تبدو غير منطقية. لذلك ، بحيث يتم تنفيذ الحدث فقط على الزر ، يمكننا ضبط عامل التصفية باستخدام طريقة infoBtn.SetPassEvents(false) .


إذا اتصلت بهذه الطريقة بهذه الطريقة ، فسيتوقف الزر عن تخطي أي أحداث تلو الأخرى. لنفترض أننا لا نريد تخطي أحداث النقر بالماوس فقط ، ثم يمكننا استدعاء طريقة ذات معلمات أخرى ، على سبيل المثال ، infoBtn.SetPassEvents(false, InputEventType.MousePress, MouseRelease) .


وبالتالي ، فمن الممكن تصفية الأحداث في كل خطوة ، وتحقيق النتيجة المرجوة.


يمكنك مرة أخرى إلقاء نظرة على التطبيق ، والذي تحول في النهاية. بالطبع ، يتم حذف تفاصيل تنفيذ منطق الأعمال هنا ، على وجه الخصوص ، توليد الشخصيات ، ومهاراتهم وأكثر من ذلك بكثير ، والتي لم تعد مرتبطة مباشرة بـ SpaceVIL. يمكن عرض رمز التطبيق الكامل على الرابط إلى GitHub ، حيث توجد بالفعل عدة أمثلة أخرى للعمل مع SpaceVIL ، سواء في C # أو Java.


لقطة شاشة لتطبيق CharacterEditor النهائي


استنتاج


في الختام ، أود أن أذكرك بأن الإطار قيد التطوير النشط ، بحيث تكون الأعطال والعطلات ممكنة ، وكذلك يمكن مراجعة بعض الميزات ويمكن أن تختلف النتيجة النهائية للاستخدام بشكل جذري عن النسخة الحالية ، وبالتالي ، إذا كان الإصدار الحالي من إطار العمل يناسبك ، فلا تنسَ نسخة احتياطية من هذا الإصدار ، لأنني لا أستطيع أن أضمن أن الإصدارات الجديدة ستكون متوافقة مع الإصدارات السابقة. يمكن إعادة صياغة بعض النقاط لزيادة راحة وسرعة استخدام SpaceVIL ولا تريد حتى الآن سحب الأفكار القديمة المهملة. أيضا ، لم يتم اختبار عمل SpaceVIL على بطاقات الفيديو من AMD ، بسبب نقص المعدات المناسبة. تم إجراء الاختبار على بطاقات الفيديو من Intel و NVidia. سوف يركز التطوير الإضافي لـ SpaceVIL على إضافة وظائف جديدة (على سبيل المثال ، لا يوجد حاليًا أي دعم للمتدرجات) والتحسين.


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


يمكنك تنزيل إطار الإصدار المطلوب وجميع الأمثلة المقدمة لبرامج الاختبار على الروابط التالية. الإصدار الأول من الوثائق متاح أيضًا هنا.


وأخيرا ، مظاهرة أكثر قليلا البصرية. فيما يلي التطبيقات المكتوبة باستخدام تقنية SpaceVIL ، والتي قد تعطيك فكرة عما يمكنك تحقيقه باستخدام SpaceVIL.


لقطات من التطبيقات المكتوبة باستخدام SpaceVIL






مراجع


Source: https://habr.com/ru/post/ar448790/


All Articles