SpaceVIL - plattformübergreifendes GUI-Framework für die Entwicklung auf .Net Core, .Net Standard und JVM

In diesem Artikel werde ich versuchen, über das SpaceVIL-Framework (Space of Visual Items Layout) zu sprechen, mit dem grafische Benutzeroberflächen auf .Net / .Net Core- und JVM-Plattformen erstellt werden.


SpaceVIL ist ein plattformübergreifendes und mehrsprachiges Framework, es basiert auf der OpenGL-Grafiktechnologie und die GLFW-Bibliothek ist für die Erstellung von Fenstern verantwortlich. Mit diesem Framework können Sie grafische Clientanwendungen unter Linux-, Mac OS X- und Windows-Betriebssystemen bearbeiten und erstellen. Für C # -Programmierer gilt dies derzeit besonders, da Microsoft WPF nicht auf andere Betriebssysteme portieren wird und Avalonia das einzig mögliche Analogon ist. Die Besonderheit von SpaceVIL in diesem speziellen Fall ist die Mehrsprachigkeit, dh derzeit kann das .Net Core-Framework in Verbindung mit den folgenden Programmiersprachen verwendet werden: C #, VisualBasic. Das JVM-Framework kann in Verbindung mit den Sprachen Java und Scala verwendet werden. Das heißt, SpaceVIL kann mit jeder dieser Sprachen verwendet werden, und der resultierende Code sieht gleich aus. Wenn Sie also zu einer anderen Sprache wechseln, müssen Sie ihn nicht erneut lernen.


SpaceVIL befindet sich noch im Alpha-Stadium, aber trotzdem kann das Framework jetzt vollständig genutzt werden, da das Framework alles enthält, was Sie zum Erstellen einer komplexen Benutzeroberfläche und zum Erstellen völlig neuer visueller Benutzerelemente benötigen. Der Zweck dieses Artikels ist genau, Sie davon zu überzeugen.


SpaceVIL wurde von Grund auf neu entwickelt und deshalb hat das Framework seine eigenen Prinzipien, die es von Analoga unterscheiden.


  • Der SpaceVIL-Benutzer hat die volle Kontrolle darüber, was passiert.
  • Jede in SpaceVIL geschriebene Anwendung sieht auf allen Plattformen genau gleich aus. Es gibt keine Fallstricke. Sie können jede Version von SpaceVIL (.Net / JVM, Mac OS X, Linux, Windows) verwenden. Das Ergebnis und das Erscheinungsbild sind immer gleich.
  • Die SpaceVIL-Version für JVM ist identisch mit der SpaceVIL-Version für .Net
  • SpaceVIL bietet Möglichkeiten zur umfassenden Anpassung eines Elements, da alle interaktiven Objekte Container für andere interaktive Objekte sind.
  • Das Framework ist sehr flexibel und einfach zu verwenden, da es nur wenige strenge Grundregeln enthält. Das einzige, was Sie verstehen müssen, bevor Sie damit arbeiten, ist, was die Einstellungen für Auffüllen, Rand, Ausrichtung bedeuten (und jeder, der einfache Schnittstellen erstellt hat, kennt sie , in WPF, Android Studio oder schrieb Stile in CSS).
  • SpaceVIL verlangt von Ihnen keine eingehende Untersuchung seiner Innenseiten und es wird genau das tun, was Sie schreiben. Alle Elemente befolgen die allgemeinen Regeln. Ein Ansatz funktioniert für alle Elemente. Wenn Sie sich an die Basis erinnert haben, können Sie sowohl die Zusammensetzung der Elemente als auch die Art und Weise ihrer Gestaltung vorhersagen.
  • Das Framework ist sehr leicht, weniger als ein Megabyte und alles in einer Datei.

Die Möglichkeiten


Nun wollen wir sehen, wozu das Framework der aktuellen Version in der Lage ist.


  • Es stehen 54 Elemente zur Verfügung, von denen 10 spezialisierte Container, 6 Grundelemente (nicht interaktive Elemente) und 38 interaktive Elemente für verschiedene Zwecke sind.
  • Basierend auf all diesen Elementen können Sie in Verbindung mit der Implementierung spezieller Schnittstellen Ihre eigenen Elemente beliebiger Komplexität erstellen.
  • Es gibt ein Styling von Elementen, es gibt Optionen zum Erstellen ganzer Stilthemen oder zum Ändern / Ersetzen des Stils eines Standardelements im Framework. Bisher ist in SpaceVIL nur ein Thema vorhanden und es ist standardmäßig installiert.
  • Es gibt ein System von Staaten. Jedem Element kann ein visueller Status für eine der Methoden der externen Beeinflussung zugewiesen werden: Bewegen des Mauszeigers über das Element, Drücken der Maustaste, Loslassen der Maustaste, Umschalten, Fokussieren und Ausschalten des Elements.
  • Es gibt eine Ereignisfilterung. Jedes Element in der Interaktion kann die Ereignisse herausfiltern, die es durchlaufen, wodurch ein Ereignis das Element passieren und vom anderen verworfen werden kann. In einem Beispiel werde ich genauer darauf eingehen.
  • Implementierung eines Systems schwebender unabhängiger Elemente.
  • Ein System von Dialogfeldern und Dialogelementen wurde implementiert.
  • Unabhängiges Rendern implementiert. Jedes Fenster verfügt über zwei Streams - einer steuert das Rendern, der andere führt Aufgaben aus eingehenden Ereignissen aus, dh das Fenster wird jetzt immer weiter gerendert (und bleibt nicht hängen), unabhängig von der Aufgabe, die nach dem Drücken einer Taste gestartet wurde.

Struktur


Betrachten wir nun die Struktur der Elemente. Die folgenden Arten von Elementen sind im Framework vorhanden: aktive und Dialogfenster, Container zum bequemen Positionieren von Elementen, interaktive Elemente und Grundelemente. Lassen Sie uns alle oben genannten Punkte kurz durchgehen. Ich hoffe, dass es nicht nötig ist, solche Fenster zu erklären. Ich stelle nur fest, dass das Dialogfeld das Fenster blockiert, das es verursacht hat, bis es geschlossen wird.


Container


Die folgenden Containertypen werden in SpaceVIL dargestellt:


  • Ein gemeinsamer Container (Elemente in einem solchen Container werden aufgrund von Ausrichtungs-, Auffüllungs-, Rand-, Größen- und Größenrichtlinienparametern positioniert).
  • Vertikale und horizontale Stapel (Elemente, die einem solchen Container hinzugefügt werden, werden in der richtigen Reihenfolge angeordnet, ohne dass die Parameter, die bei Verwendung des vorherigen Containertyps erforderlich sind, genau eingestellt werden müssen).
  • Gitter - Elemente werden zu den Gitterzellen hinzugefügt und in ihrer Zelle positioniert.
  • List (ListBox, TreeView), ein Container, der auf einem vertikalen Stapel basiert, aber einen Bildlauf durchführen kann, um Elemente anzuzeigen, die nicht in den Container passen.
  • Separator (SplitArea), ein Container kann von zwei Arten sein - vertikal und horizontal, trennt zwei Bereiche und steuert interaktiv die Größe dieser Bereiche.
  • Tabbed Container (TabView) steuert die Sichtbarkeit der Seite.
  • WrapGrid positioniert Elemente in Zellen einer bestimmten Größe und füllt den gesamten freien Speicherplatz entsprechend der Ausrichtung mit der Möglichkeit des Bildlaufs aus (das auffälligste Beispiel ist Windows Explorer im Symbolanzeigemodus).
  • Und schließlich ist ein freier Container, wahrscheinlich der seltenste Container, ein unendlicher Bereich, in den Sie Elemente fester Größe einfügen können. Es ist jedoch besser, ihn in Kombination mit einem Element vom Typ ResizableItem zu verwenden.

Interaktive Elemente


Elemente dieses Typs akzeptieren viele Zustände und haben verschiedene Ereignisse. Wenn es einfacher ist, gibt es alles, mit dem Sie interagieren können, und interaktive Elemente, z. B. eine Schaltfläche, ein Kontrollkästchen, ein Element zur Texteingabe und andere.


Primitive


Im Gegensatz zu interaktiven Elementen gibt es Grundelemente, völlig nicht interaktive Elemente, es ist unmöglich, sie zu kontaktieren, sie existieren nur, um sich zu zeigen. Arten von Grundelementen: ein Dreieck, ein Rechteck, eine Ellipse und etwas komplizierter - eine beliebige Figur, die die Form einer beliebigen Komplexität annehmen kann.


Es gibt auch statische Serviceklassen. Einige dieser Klassen ermöglichen es dem Programmierer, Elemente nach ihren Wünschen abzurufen und anzupassen. Beispielsweise gibt es eine Klasse, die die Stile von Elementen steuert, und eine Klasse, mit der Sie ein beliebiges Anzeigeformular für ein interaktives Element, eine Klasse von Standardeinstellungen usw. festlegen können.


Ein Beispiel für eine einfache Anwendung mit dem SpaceVIL-Framework


Ich habe eine kleine Modeerscheinung über Beispiele. Sie können immer ein abstraktes und genau reflektierendes Funktionsbeispiel erstellen, aber wenn Sie es von der Seite lesen, sieht es immer sehr wenig überzeugend aus. Als Beispiel versuche ich, kleine, aber vorgefertigte Anwendungen zu erstellen, die einem verständlichen Zweck dienen.


Fahren wir mit der Beschreibung der Anwendung fort. Das Programm ist ein Heldenkarten-Editor für Spiele wie "Dungeons and Dragons" und trägt den Namen CharacterEditor. Das Programm generiert zufällig eine bestimmte Anzahl verschiedener Zeichen mit Namen, Alter, Rasse, Geschlecht, Klasse und Merkmalen. Der Benutzer hat die Möglichkeit, eine Biografie zu schreiben und dem Charakter spezielle Fähigkeiten zu vermitteln. Als Ergebnis können Sie die Heldenkarte als Textdatei speichern. Kommen wir zur Code-Analyse. Das Programm ist in C # geschrieben. Bei Verwendung von Java ist der Code im Wesentlichen derselbe.


Als Ergebnis erhalten wir eine solche Anwendung:



Anwendungsfenster erstellen


An dieser Stelle erstellen wir ein Fenster. Ich möchte Sie daran erinnern, dass SpaceVIL GLFW verwendet. Wenn Sie also eine Anwendung für die .Net-Plattform schreiben, muss die kompilierte GLFW-Bibliothek neben die ausführbare Datei kopiert werden. Die JVM verwendet den GLFW-Bibliotheks-Wrapper (LWJGL), dessen Zusammensetzung bereits eine kompilierte GLFW enthält.


Füllen Sie anschließend den Rendering-Bereich mit den erforderlichen Elementen und geben Sie ihnen ein schönes Aussehen. Die Hauptschritte, um dies zu erreichen, sind wie folgt:


  • Initialisieren von SpaceVIL vor der Verwendung. Schreiben Sie in der Hauptfunktion einfach:

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

  • Erstellen Sie nun ein Fenster. Dazu müssen Sie eine Fensterklasse schreiben, die sie von der SpaceVIL.ActiveWindow Klasse SpaceVIL.ActiveWindow , die InitWindow() -Methode beschreiben und mit mehreren grundlegenden Parametern wie Fenstername, Titelleisten-Text und Abmessungen festlegen. Als Ergebnis erhalten wir einen Code, der folgendermaßen aussieht:

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

  • Es bleibt nur eine Instanz dieser Klasse zu erstellen und aufzurufen. Dazu ergänzen wir die Main-Methode mit folgenden Codezeilen:

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

Das ist alles, in diesem Stadium können Sie die Anwendung starten und prüfen, ob alles funktioniert.


Füllen mit Elementen


Um CharacterEditor zu implementieren, habe ich beschlossen, eine Titelleiste, eine Symbolleiste und einen vertikalen Teiler in das Fenster einzufügen. Die Symbolleiste enthält: eine Schaltfläche zum Aktualisieren der Liste der neu generierten Zeichen, eine Schaltfläche zum Speichern des Zeichens und ein Element mit der Anzahl der generierten Zeichen. Auf der linken Seite des vertikalen Trennzeichens befindet sich eine Liste der generierten Zeichen und auf der rechten Seite ein Textbereich zum Bearbeiten eines aus der Liste ausgewählten Zeichens. Um die Fensterklasse nicht mit Elementeinstellungen zu überladen, können Sie eine statische Klasse schreiben, die uns Elemente bereitstellt, die in Aussehen und Einstellungen bereit sind. Beachten Sie beim Hinzufügen, dass jedes interaktive Element, ob es sich um eine Schaltfläche oder eine Liste handelt, ein Container ist. Sie können also alles von einer Schaltfläche bis zu Primitiven in einen anderen Container einfügen, und jedes komplexe Element ist nur eine Reihe einfacherer Elemente, die insgesamt dienen ein Ziel. Wenn Sie dies wissen, müssen Sie sich an die erste strenge Regel erinnern - bevor Sie einem Element andere Elemente hinzufügen, müssen Sie es irgendwo hinzufügen, entweder zur Fensterklasse selbst (in unserem Fall MainWindow ) oder zu einem Container oder einem anderen interaktiven Element. Lassen Sie uns anhand eines Beispiels erklären:


 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); } 

Es ist richtig, zuerst dem Fenster einen frame hinzuzufügen und dann dem frame eine Schaltfläche hinzuzufügen. Es scheint, dass die Regel sehr unpraktisch ist und Sie beim Erstellen eines komplexen Fensters schwitzen müssen. Aus diesem Grund empfiehlt SpaceVIL, eigene Elemente zu erstellen, was das Hinzufügen von Elementen erheblich vereinfacht. Ich werde etwas später die Entstehung meiner eigenen Elemente zeigen und erklären. Kommen wir zurück zur Anwendung. Hier ist das resultierende Fenster:



Analysieren wir nun den Code:


MainWindow Markup-Zusammenfassungscode
 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))); } 

In der ItemFactory Klasse habe ich das Erscheinungsbild und Layout von Elementen beschrieben. Die ItemFactory.GetToolbarButton() -Methode sieht beispielsweise ItemFactory.GetToolbarButton() aus:


 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; } 

Die übrigen Elemente werden ähnlich beschrieben.


Stile erstellen und anwenden


Wie Sie vielleicht bemerkt haben, habe ich dem ItemText Element einen Stil ItemText . Schauen wir uns also an, wie Stile erstellt werden, und schauen wir uns zunächst den Stilcode an:


 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);//   

Wie Sie sehen können, habe ich für dieses Element einen vorgefertigten Stil aus der SpaceVIL.Style Klasse übernommen und ihn leicht geändert, um die Farben zu korrigieren. Jeder Stil kann mehrere interne Stile zum Stylen jedes einzelnen komplexen Elements enthalten. Ein CheckBox Element besteht beispielsweise aus einem Container, einem Indikator und einem Text, sodass sein Stil interne Stile für den Indikator ("Indikator") und den Text ("Textzeile") enthält.


Die Style Klasse deckt alle visuellen Eigenschaften von Elementen ab. Darüber hinaus können Sie mithilfe des Stils die Form eines Elements interaktiv ändern, z. B. von einer Ellipse zu einem Rechteck und umgekehrt. Um einen Stil anzuwenden, müssen Sie die SetStyle(Style style) Methode SetStyle(Style style) für das Element aufrufen, wie oben bereits gezeigt:


 ItemText.SetStyle(StyleFactory.GetTextAreaStyle()); 

Erstellen Sie Ihren eigenen Artikel


Fahren wir nun mit der Erstellung des Elements fort. Das Element selbst muss nicht spezifisch sein, es kann ein regulärer Stapel sein, in dem Sie mehrere andere Elemente hinzufügen. Im obigen Beispiel habe ich beispielsweise eine Symbolleiste, in der drei Elemente enthalten sind. Die Symbolleiste selbst ist nur ein horizontaler Stapel. Alles könnte als separates Element angeordnet und als ToolBar bezeichnet werden. An sich tut es nichts, aber in der MainWindow Klasse würde die Anzahl der Zeilen reduziert und das Verständnis des Markups wäre noch einfacher, außerdem ist es auch eine Möglichkeit, die erste strenge Regel zu schwächen, obwohl am Ende natürlich alles gehorcht. Okay, wir berühren die Symbolleiste nicht mehr. Wir benötigen ein Element für die Liste, das das generierte Zeichen anzeigt.


Um es interessanter zu machen, definieren wir die Zusammensetzung des Elements komplizierter:


  • Ein Charaktersymbol, dessen Farbe die Zugehörigkeit zu einer Fantasy-Rasse anzeigt.
  • Name, Nachname und Rasse des Charakters in Textform.
  • Zeichen-Schnellhilfetaste (wird benötigt, um Filterereignisse zu demonstrieren).
  • Schaltfläche zum Löschen des Zeichens, falls es nicht zu uns passt.

Um eine Klasse Ihres eigenen Elements zu erstellen, müssen Sie sie von jedem interaktiven Element von SpaceVIL erben, wenn mindestens eine Klasse in ihrer Zusammensetzung zu uns passt. Für das aktuelle Beispiel werden wir das Element jedoch von Grund auf neu zusammenstellen und es daher von der abstrakten Basisklasse interaktiver Elemente - SpaceVIL.Prototype - SpaceVIL.Prototype . Wir müssen auch die InitElements() -Methode implementieren, in der wir das Erscheinungsbild des Elements, die Position und den Typ verschachtelter Elemente sowie die Reihenfolge des Hinzufügens verschachtelter Elemente beschreiben. Das Element selbst heißt CharacterCard .


Fahren wir mit dem Parsen des Codes des fertigen Elements fort:


CharacterCard-Artikelcode
 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(); } } } 

In dem Beispiel habe ich eine Hilfsklasse verwendet, die alle grundlegenden Merkmale des Charakters wie Name, Nachname, Rasse, Geschlecht, Alter, Spezialisierungsklasse, Merkmale, Fähigkeiten und Biografie enthält. In dieser Klasse werden alle Parameter außer Fähigkeiten und Biografie (es wird davon ausgegangen, dass der Benutzer sie unabhängig erfindet) generiert.


Ereignisverarbeitung und Filterung


Im vorherigen Beispiel wurden zwei Arten von Ereignissen beschrieben: MouseHover und MouseClick. Derzeit gibt es nur 11 Basisereignisse. Hier ist die Liste:


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

Komplexe Elemente haben ihre eigenen einzigartigen Ereignisse, aber die oben genannten Ereignisse stehen (mit Vorbehalt) jedem zur Verfügung.


Die Syntax für die Ereignisbehandlung ist trivial und sieht folgendermaßen aus:


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

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

Fahren wir nun mit dem Filtern von Ereignissen fort. Standardmäßig durchlaufen Ereignisse eine Pyramide von Elementen. In unserem Beispiel erhält die Schaltfläche infoBtn das Ereignis des infoBtn auf die Schaltfläche auf der infoBtn Schaltfläche. Dieses Ereignis empfängt dann das CharacterCard Element, dann die ListBox in der es sich befindet, dann SplitArea , VerticalStack und am Ende das grundlegende Wontainer Element.


Für jedes Element können Sie das EventMouseClick Ereignis verarbeiten, und alle diese Aktionen werden in der angegebenen Reihenfolge ausgeführt. Was ist jedoch, wenn wir beim Klicken auf ein Element nicht möchten, dass dieses Ereignis weiter entlang der Kette verläuft? Dafür gibt es nur eine Ereignisfilterung. Lassen Sie uns beispielsweise das CharacterCard Element deutlicher darstellen. Stellen Sie sich vor, CharacterCard beschreibt das EventMouseClick Ereignis, bei dem Informationen aus der verknüpften CharacterInfo in ein Textfeld zum Bearbeiten eines Zeichens EventMouseClick . Dieses Verhalten ist logisch - wir klicken auf das Element und sehen alle Parameter des Zeichens. Als nächstes bearbeiten wir den Charakter, erfinden eine Biografie und Fähigkeiten oder ändern die Eigenschaften. Irgendwann wollten wir eine kurze Information über ein anderes generiertes Zeichen aus der Liste sehen und auf die Schaltfläche infoBtn klicken. Wenn wir die Ereignisse nicht filtern, wird EventMouseClick nach dem Aufrufen des Tooltips für das CharacterCard Element selbst ausgeführt, das, wie wir uns erinnern, Text in das Zeichenbearbeitungsfeld einfügt, was zum Verlust von Änderungen führt, wenn wir die Ergebnisse nicht speichern, und das Verhalten der Anwendung selbst wird unlogisch aussehen. Daher können wir den Filter mit der Methode infoBtn.SetPassEvents(false) , damit das Ereignis nur auf der Schaltfläche ausgeführt wird.


Wenn Sie diese Methode auf diese Weise aufrufen, überspringt die Schaltfläche keine Ereignisse mehr nach sich selbst. Angenommen, wir möchten nicht nur Mausklickereignisse überspringen, infoBtn.SetPassEvents(false, InputEventType.MousePress, MouseRelease) eine Methode mit anderen Parametern aufrufen, z. B. infoBtn.SetPassEvents(false, InputEventType.MousePress, MouseRelease) .


Somit ist es möglich, Ereignisse bei jedem Schritt zu filtern, um das gewünschte Ergebnis zu erzielen.


Sie können sich noch einmal die Anwendung ansehen, die sich am Ende herausgestellt hat. Natürlich werden hier Details zur Implementierung der Geschäftslogik weggelassen, insbesondere die Generierung von Charakteren, ihre Fähigkeiten und vieles mehr, was nicht mehr direkt mit SpaceVIL zusammenhängt. Der vollständige Anwendungscode kann über den Link zu GitHub eingesehen werden. Dort gibt es bereits einige andere Beispiele für die Arbeit mit SpaceVIL, sowohl in C # als auch in Java.


Screenshot der fertigen CharacterEditor-Anwendung


Fazit


Abschließend möchte ich Sie daran erinnern, dass sich das Framework in der aktiven Entwicklung befindet, sodass Abstürze und Abstürze möglich sind sowie einige Funktionen überarbeitet werden können und das Endergebnis der Verwendung radikal von dem aktuellen abweichen kann. Wenn die aktuelle Version des Frameworks zu Ihnen passt, vergessen Sie dies nicht Backup dieser Version, da ich nicht garantieren kann, dass neue Versionen abwärtskompatibel sind. Einige Punkte können wiederholt werden, um den Komfort und die Geschwindigkeit der Verwendung von SpaceVIL zu erhöhen, und möchten bisher keine alten und verworfenen Ideen in die Länge ziehen. Außerdem wurde die Arbeit von SpaceVIL aufgrund fehlender Ausrüstung nicht auf Grafikkarten von AMD getestet. Die Tests wurden mit Grafikkarten von Intel und NVidia durchgeführt. Die Weiterentwicklung von SpaceVIL wird sich auf das Hinzufügen neuer Funktionen (zum Beispiel gibt es derzeit keine Unterstützung für Farbverläufe) und die Optimierung konzentrieren.


Ich möchte auch eine Einschränkung erwähnen, die beim Schreiben einer plattformübergreifenden Anwendung mit dieser Technologie beachtet werden sollte. Es wird nicht empfohlen, Dialogfelder zu verwenden (und im Allgemeinen aufgrund von Renderfehlern Anwendungen mit mehreren Fenstern unter Linux zu erstellen). Dialogfelder können leicht durch Dialogelemente ersetzt werden. Mac OS X verbietet im Allgemeinen die Erstellung von Anwendungen mit mehreren Fenstern, da die GUI nur im Hauptanwendungsthread gestartet werden muss.


Sie können das Framework der erforderlichen Version und alle vorgestellten Beispiele für Testprogramme unter den folgenden Links herunterladen. Die erste Version der Dokumentation finden Sie auch hier.


Zum Schluss noch eine visuelle Demonstration. Im Folgenden finden Sie Anwendungen, die mit der SpaceVIL-Technologie geschrieben wurden und Ihnen möglicherweise eine Vorstellung davon geben, was Sie mit SpaceVIL erreichen können.


Screenshots von Anwendungen, die mit SpaceVIL geschrieben wurden






Referenzen


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


All Articles