info@a-coding-project.de

JScript.net: Fensteranwendungen erstellen

Bis hierher sahen die JScript.NET-Anwendungen noch etwas fade aus und man konnte mit ihnen nichts so recht anfangen. Damit das nicht so bleibt, besteht die Möglichkeit Fensteranwendungen zu erstellen. Eine Fensteranwendung ist nichts als ein normales Windows-Programm: Eben ein Fenster mit grafischen Symbolen, Eingabefeldern usw.

Ein Fenster erstellen

Ein Fenster bildet die Grundlage jeder modernen Anwendung. Das .NET-Framework besitzt dazu die Klasse Form die im Namespace System.Windows.Forms enthalten ist. Sie enthält die Fensterdefinitionen. Um eine Fensteranwendung erstellen zu können, muss ein Package definiert werden, dass als Anwendung fungieren soll. Dem Package können dann Klasse gegeben werden, die von diesem Namespace her abgeleitet sind. Jede Klasse kann dann ein Objekt als Fenster erstellen und anzeigen.

Als erstes sollten - wie immer - die nötigen Namespaces importiert werden. Für ein erstes Beispiel benötigen wir System, System.Windows.Forms, System.ComponentModel und System.Drawing:

import System;
import System.Windows.Forms;
import System.ComponentModel;
import System.Drawing;

Das Beispielpackage wird hier Anwendung genannt und mit einer Klasse Hauptfenster versehen. Außerdem wird dem Fenster eine Reihe von Komponenten wie Textfelder oder Buttons zugeordnet, die jeweils als Eigenschaften definiert werden. Ebenso erzeugen wir einen vorläufigen Konstruktor der Klasse:

package Anwendung
{
 class Hauptfenster extends System.Windows.Forms.Form 
 {
  private var Ueberschrift : Label;
  private var Eingabe : TextBox;
  private var Ausgabe : TextBox;
  private var Knopf : Button; 

  public function Hauptfenster()
  {
   // ...
  }
 }
}

Um die Anwendung starten zu lassen, muss nichts weiter getan werden, als sie vom Skript ausführen zu lassen. Das geschieht mit Hilfe des Application-Objekts, das automatisch vom Namespace System.Windows.Forms bereitgestellt wird. Es besitzt die Run-Methode, die eine Anwendung erstellt und startet. Dieser wird ein Fensterobjekt übergeben, das als Hauptfenster der Anwendung fungieren soll:

Application.Run(new Anwendung.Hauptfenster());

Als Resultat wird ein (noch) leeres Fenster angezeigt:

Eine erste Fensteranwendung - noch ohne Inhalt
Darstellung: Eine erste Fensteranwendung - noch ohne Inhalt

Fenster mit Leben füllen

Da eine Anwendung ja nicht nur aus einem leeren Fenster bestehen kann, muss sie mit etwas "Leben" gefüllt werden. Im obigen Beispiel wurde dazu schon ein Label, zwei Textboxen und ein Knopf erstellt. Innerhalb des Konstruktors des Fensters sollten nun alle Elemente initialisiert und angeordnet werden. Das Erstellen sollte soweit kein Problem sein. Zur Positionierung besitzen die meisten Komponenten eine Location-Eigenschaft, die eine Koordinate erwartet. Die Koordinaten werden hier wie bei Browserfenstern gehandhabt: Die Koordinate (0;0) ist ganz oben links - die x-Koordinate wandert nach rechts und die y-Koordinate entsprechend nach unten. Eine neue Koordinate wird mit new Point(x,y) erstellt, wobei x und y die zu setzenden Werte in horizontaler und vertikaler Richtung sind.

Sind die Elemente erstellt und ausgerichtet benötigen Sie zumeist noch etwas "Gestaltung". Dem Label wird ein Text (Text-Eigenschaft) gegeben, dem Button eine Aufschrift (ebenfalls Text-Eigenschaft) und den beiden Textboxen geben wir einen Inhalt (auch hier ist es die Text-Eigenschaft). Zudem müssen die Größen der Elemente angepaßt werden. Dies geschieht über die Size-Eigenschaft, der ein neues System.Drawing.Size-Objekt übergeben wird. Soweit sieht der Konstruktor so aus:

Ueberschrift = new Label();
   Ueberschrift.Location = new Point(20,10);
   Ueberschrift.Size = new System.Drawing.Size(100,30);
   Ueberschrift.Text = 'JScript.NET';

   Eingabe = new TextBox();
   Eingabe.Location = new Point(20,40);
   Eingabe.Size = new System.Drawing.Size(80,25);
   Eingabe.Text = 'Eingabe';

   Ausgabe = new TextBox();
   Ausgabe.Location = new Point(105,40);
   Ausgabe.Size = new System.Drawing.Size(80,25);
   Ausgabe.Text = 'Ausgabe';

   Knopf = new Button();
   Knopf.Location = new Point(105,70);
   Knopf.Size = new System.Drawing.Size(80,25);
   Knopf.Text = 'Ausgabe';

Ein erneutes Kompilieren erzeugt jedoch immer noch ein leeres Fenster. Die Elemente wurden zwar erstellt, aber nicht mit dem Fenster verbunden. Dazu fügen wir die Elemente der Controls-Kollektion des Fensters hinzu:

this.Controls.Add(Ueberschrift);
   this.Controls.Add(Eingabe);
   this.Controls.Add(Ausgabe);
   this.Controls.Add(Knopf);

Das jetzige Resultat kann sich schon fast sehen lassen. Noch ein paar kleinere Korrekturen und die Anwendung hat schon mal das richtige Aussehen. Der vollständige Quellcode des Konstruktors:

Ueberschrift = new Label();
   Ueberschrift.Location = new Point(20,10);
   Ueberschrift.Size = new System.Drawing.Size(100,30);
   Ueberschrift.Text = 'JScript.NET';
   Ueberschrift.AutoSize = true;
   Ueberschrift.Font = new System.Drawing.Font(
                         new FontFamily('Times New Roman').Name,
                         18,FontStyle.Bold);

   Eingabe = new TextBox();
   Eingabe.Location = new Point(20,40);
   Eingabe.Size = new System.Drawing.Size(80,25);
   Eingabe.Text = 'Eingabe';

   Ausgabe = new TextBox();
   Ausgabe.Location = new Point(105,40);
   Ausgabe.Size = new System.Drawing.Size(80,25);
   Ausgabe.Text = 'Ausgabe';

   Knopf = new Button();
   Knopf.Location = new Point(105,70);
   Knopf.Size = new System.Drawing.Size(80,25);
   Knopf.Text = 'Ausgabe';

   this.Controls.Add(Ueberschrift);
   this.Controls.Add(Eingabe);
   this.Controls.Add(Ausgabe);
   this.Controls.Add(Knopf);

   this.Text = 'JScript.NET';
   this.ClientSize = new System.Drawing.Size(205,105); 
   this.StartPosition = 
             System.Windows.Forms.FormStartPosition.CenterScreen;

Kompiliert sieht das dann so aus:

Das kompilierte Resultat einer ersten Anwendung
Darstellung: Das kompilierte Resultat einer ersten Anwendung

Mit Events Arbeiten

Im obigen Beispiel wurde zwar ein Button erstellt - jedoch macht dieser noch nicht viel als gut aussehen. Um ihm Leben einzuhauchen müssen - wie bei normalen Webdokumenten auch - Events definiert werden. Da in JScript.NET die Ereignisse der Fensterelemente alle geschützt sind, muss ein Umweg gegangen werden - eine einfache Zuweisung funktioniert also nicht. Das .NET-Framework ist in dieser Hinsicht leider etwas unstrukturiert aufgebaut. Jede einzelne Sprache unterstützt zumeist eine von den anderen Sprachen sehr erheblich abweichende Syntax zur Definition von Ereignissen. In JScript.NET wird dazu eine mehr als unkonventionelle Verfahrensweise eingeführt die es so wahrscheinlich in noch keiner Sprache gab: Um einem Objekt einen Event-Handler zuzuweisen, wird für jedes Event eine eigene Methode verwendet. Diese Methoden sind leider nicht in der Hilfe des .NET-SDK beschrieben, sie folgen jedoch alle der gleichen Schreibweise. Der Methodenname setzt sich jeweils aus dem Wort add, einem Unterstrich und dem Namen des Events zusammen. Soll beispielsweise dem Click-Ereignis des Buttons aus dem obigen Beispiel eine Funktion zugewiesen werden, so heißt die entsprechende Methode add_Click, bei einem MouseOver-Ereignis wäre es dann die Methode add_MouseOver usw. Der Methode wird jeweils die Funktion als Konstante übergeben die das Ereignis behandeln soll (eben der Event-Handler). Wird das Ereignis aufgerufen, erhält es automatisch zwei Parameter: Meist sind das ein Object-Objekt und ein EventArgs-Objekt - beide sollten also in der Funktionsdefinition vorgesehen werden. Außerdem darf ein Event-Handler keinen Wert zurückgeben. Als Beispiel die Vervollständigungen des obigen Quellcodes:

//...
package Anwendung
{
 class Hauptfenster extends System.Windows.Forms.Form 
 {
  //...

  public function Hauptfenster()
  {
   //...

   Knopf = new Button();
   Knopf.Location = new Point(105,70);
   Knopf.Size = new System.Drawing.Size(80,25);
   Knopf.Text = 'Ausgabe';
   Knopf.add_Click(KnopfKlick);
  }
  
  function KnopfKlick(o:Object, e:EventArgs)
  {
   Ausgabe.Text = Eingabe.Text;
   Eingabe.Text = '';
  }
 }
}
//...

Das vorgestellte Beispiel kopiert bei Klick auf den Button den Inhalt des Eingabe-Feldes in den Inhalt des Ausgabe-Feldes. Anschließend wird die Eingabe geleert.

Mit mehreren Fenstern arbeiten

Eine Anwendung besteht ja zumeist nicht nur aus einem Fenster. Dementsprechend besteht natürlich auch die Möglichkeit Anwendungen mit mehreren Fenstern zu erstellen. Dazu müssen lediglich mehrere Fenster-Klassen erstellt werden, die jeweils initialisiert und angezeigt werden. Der folgende Code zeigt eine einfache Anwendung mit zwei Fenstern:

import System;
import System.Windows.Forms;
import System.ComponentModel;
import System.Drawing;

package Anwendung
{
 class Hauptfenster extends System.Windows.Forms.Form 
 {
  private var Knopf : Button;
  private var Ufenster : Unterfenster;

  public function Hauptfenster()
  {
   Knopf = new Button();
   Knopf.Location = new Point(2,2); 
   Knopf.Size = new System.Drawing.Size(80,25);
   Knopf.Text = 'Neues Fenster'; 
   Knopf.add_Click(KnopfKlick);
   Ufenster = new Unterfenster();
   this.Controls.Add(Knopf); 
   this.Text = 'Hauptfenster';
   this.ClientSize = new System.Drawing.Size(150,29); 
  }

  function KnopfKlick(o:Object, e:EventArgs)
  { Ufenster.Show(); }

  class Unterfenster extends System.Windows.Forms.Form 
  {
   public function Unterfenster()
   {
    this.Text = 'Unterfenster';
    this.ClientSize = new System.Drawing.Size(150,29); 
    this.add_Closing(Schliessen);
   }
   
   function Schliessen(o:Object, e:CancelEventArgs)
   { e.Cancel = true; this.Hide(); }
  }
 }
}
Application.Run(new Anwendung.Hauptfenster());

Im obigen Beispiel wird ein ganz normales Fenster als Klasse Hauptfenster definiert und erzeugt. Das Fenster enthält einen Button (Knopf) auf dessen Click-Ereignis ein weiteres Fenster (Ufenster) geöffnet werden soll. Das zweite Fenster ist entsprechend als Klasse Unterfenster definiert. Das Hauptfenster besitzt zum Zugriff auf das Unterfenster die Eigenschaft Ufenster vom Typ Unterfenster.
Wichtig dabei: Dem Ufenster wird ein Event-Handler für das Closing-Ereignis zugewiesen. Das Closing-Ereignis tritt immer dann ein, wenn das Fenster geschlossen werden soll (z.B. weil der Benutzer auf das Schließen-X klickt). Beim Schließen des Fensters wird jedoch die Instanz des Fensters zerstört und müsste somit erst wieder erneut initialisiert werden um es erneut anzuzeigen. Damit das nicht sein muss, wird das Ereignis abgefangen und das Zerstören des Fensters verhindert (e.Cancel = true;). Um dem Benutzer dennoch vorzugaukeln, das Fenster sei weg, wird das Fenster versteckt (this.Hide();). Für den Benutzer ist das Fenster nun nicht mehr sichtbar - es bleibt aber weiterhin initialisiert.

Die verschiedenen Komponenten verwenden

Neben den bereits vorgestellten Komponenten wie Buttons, Textboxen oder Labels gibt es noch eine ganze Zahl weiterer Komponenten. Alle können hier natürlich nicht vorgestellt werden. Am Beispiel dreier Komponenten soll beispielhaft das Erstellen dieser Komponenten demonstriert werden:

Menüs

Menüs sind eine wichtige Komponente. Sie fassen die wichtigsten Funktionen eines Programms übersichtlich und jederzeit verwendbar zusammen. Fast jedes Programm verwendet zumindest ein Hauptmenü - und sei es nur um das Programm zu schließen. Ein einfaches Hauptmenü kann wie folgt erstellt werden:

class Hauptfenster extends System.Windows.Forms.Form 
 {
  var Hauptmenue : MainMenu;
  var m_Info:MenuItem, m_Info2:MenuItem, m_Info3:MenuItem;
  var m_Programm:MenuItem, m_Ende:MenuItem;

  public function Hauptfenster()
  {
   Hauptmenue = new MainMenu();
   m_Info = new MenuItem();     m_Info.Text = '?';
   m_Info2 = new MenuItem();    m_Info2.Text = 'Der Autor';
   m_Info3 = new MenuItem();    m_Info3.Text = 'Webseite';
   m_Info3.add_Click(SagAn);

   m_Programm = new MenuItem(); m_Programm.Text = 'Programm';
   m_Ende = new MenuItem();     m_Ende.Text = 'Beenden';
   m_Ende.add_Click(Beenden);

   m_Programm.MenuItems.Add(m_Ende); 
   m_Info.MenuItems.Add(m_Info2);
   m_Info2.MenuItems.Add(m_Info3);
   Hauptmenue.MenuItems.Add(m_Programm);
   Hauptmenue.MenuItems.Add(m_Info);
   this.Menu = Hauptmenue;
   this.ClientSize = new System.Drawing.Size(300,300); 
  }
   
  function Beenden(o:Object, e:EventArgs)
  {Application.Exit();}
  function SagAn(o:Object, e:EventArgs)
  {MessageBox.Show("https://www.a-coding-project.de");}
 }

Wie im Beispiel dargestellt wird für ein Hauptmenü die Komponente MainMenu benötigt. Jeder Untereintrag ist vom Typ MenuItem, die jeweils über die MenuItems.Add-Methode eingefügt werden können. Direkte Untereinträge des Hauptmenüs werden nebeneinander dargestellt (hier Programm und ?), alle weiteren Untereinander (z.B. Beenden) bzw. mit Verzweigung (Webseite) dargestellt.

Toolbars

Toolbars sind Schaltflächen mit einem oder mehreren Buttons. Die meisten Programme verwenden Toolbars um Funktionen wie "Neues Dokument", "Speichern" oder "Laden" schnell zugänglich zu machen. Ein Beispiel für das Erstellen von Toolbars:

class Hauptfenster extends System.Windows.Forms.Form 
 {
  var Toolbar1 : ToolBar;
  var Neu: ToolBarButton;
  var Laden: ToolBarButton;
  var Speichern : ToolBarButton;

  public function Hauptfenster()
  {
   Toolbar1 = new ToolBar();
   Toolbar1.ImageList = new ImageList();
   Toolbar1.ImageList.Images.Add(Image.FromFile('neu.bmp'));
   Toolbar1.ImageList.Images.Add(Image.FromFile('laden.bmp'));
   Toolbar1.ImageList.Images.Add(Image.FromFile('speich.bmp'));

   Neu = new ToolBarButton(); Neu.Text = 'Neues Dokument';
   Neu.ImageIndex = 0;
   Laden = new ToolBarButton(); Laden.Text = 'Laden'
   Laden.ImageIndex = 1;
   Speichern = new ToolBarButton(); Speichern.Text = 'Speichern';
   Speichern.ImageIndex = 2;

   Toolbar1.Buttons.Add(Neu);
   Toolbar1.Buttons.Add(Laden);
   Toolbar1.Buttons.Add(Speichern);

   this.Controls.Add(Toolbar1);
   this.ClientSize = new System.Drawing.Size(300,300); 
  }   
 }

Eine Toolbar ist vom Typ ToolBar, die einzelnen Buttons vom Typ ToolBarButton. Außerdem besitzt die ToolBar die Eigenschaft ImageList. Eine ImageList ist (wie der Name schon andeutet) eine Liste von Bildern, die hier mit der Add-Methode hinzugefügt werden. Über die Eigenschaft ImageIndex eines Buttons kann das zu verwendende Bild für den Button bestimmt werden. Das erste Bild hat den Index 0, das zweite 1 usw.

Dialoge

Neben sichtbaren Komponenten besitzt das .NET-SDK auch eine ganze Reihe von nicht sichtbaren Komponenten oder Komponenten die nur zeitweise sichtbar sind - Dialoge gehören z.B. dazu. Ein Dialog ist ein schon vorgefertigtes Fenster, in dass z.B. bestimmte Eingaben getätigt werden können. Jeder sollte solche Dialoge kennen - das Speichern- oder Laden-Fenster ist ein solcher Dialog. Der folgende Code zeigt beispielhaft die Verwendung eines Laden-Dialogs:

class Hauptfenster extends System.Windows.Forms.Form 
 {
  private var Knopf : Button;
  private var oeffnen : OpenFileDialog;

  public function Hauptfenster()
  {
   Knopf = new Button();
   Knopf.Location = new Point(5,5);
   Knopf.Size = new System.Drawing.Size(80,25);
   Knopf.Text = 'Laden';
   Knopf.add_Click(KnopfKlick);

   oeffnen = new OpenFileDialog();
   oeffnen.Filter = 'Textdateien (*.txt)|*.txt|'+
                    'Alle Dateien (*.*)|*.*';

   this.Controls.Add(Knopf);
   this.Text = 'JScript.NET';
   this.ClientSize = new System.Drawing.Size(35,90); 
  }
  
  function KnopfKlick(o:Object, e:EventArgs)
  {
   if(oeffnen.ShowDialog() == 'OK')
   { MessageBox.Show('Eine Datei wurde ausgewählt: '+
                      oeffnen.FileName); }
   else
   { MessageBox.Show('Es wurde auf Abbrechen geklickt'); }
  }
 }

Das Formular definiert einen Button und einen Laden-Dialog des Typs OpenFileDialog. Als erstes wird dazu der Dateifilter (Filter-Eigenschaft) bestimmt. Ein Filter besteht je aus zwei Werten die durch Abwärtsstriche (|) voneinander getrennt werden: Eine Beschreibung und eine durch Semikolons getrennte Liste von Dateiformaten. Mehrere Filter werden ebenfalls durch einen Abwärtsstrich voneinander getrennt. Um den Dialog aufzurufen wird die ShowDialog-Methode aufgerufen. Sie gibt - je nach dem wie der Dialog ausgewertet wurde - einen entsprechenden Wert aus.

Andere Komponenten

Wie an diesen zwei Beispielen ersichtlich, ist der Ablauf für die Erstellung komplexer Komponenten immer der selbe: Es wird die Hauptkomponente erstellt und dieser werden die Unterkomponenten hinzugefügt. Wichtig ist hierbei auch wieder ein Blick in die Dokumentation des .NET-SDK. Zumeist sind hier schon Beispiele zu finden die das Erstellen einer bestimmten Komponente zeigen oder die zumindest den Umgang mit dieser veranschaulichen.

Weiterlesen: ⯈ Änderungen bestehender Syntax

Über uns

Stefan Wienströer

Wir entwickeln Webanwendungen mit viel Leidenschaft. Unser Wissen geben wir dabei gerne weiter. Mehr über a coding project

Auch interessant