Seite 1 von 3

GUI-Aspekte

Verfasst: 14.07.2005 10:06:29
von Roland Ziegler
Zur Kommunikation liegen bereits diverse Erkenntnisse vor, zur Konfiguration habe ich auch schon mal ein paar Gedanken in den Raum gestellt, und nun habe ich mich ein wenig mit Überlegungen zur Benutzeroberfläche (GUI) beschäftigt.

Ein schon früher von mir geäußertes Kriterium ist Trennung von Form und Funktion. Stellwerkslogik und deren Bedienung bzw. Visualisierung sind zwei verschiedene Dinge, die auch softwareseitig getrennt werden sollen. Ob das im Endeffekt auch zwei Prozesse sein müssen, sei mal dahingestellt, ich gehe im Moment von einem Prozess aus, aber mit klarer Trennung im Inneren, also z.B. durch separate Namensräume in separaten Assemblies/DLLs.

Die Stellwerkslogik fürs mechanische Stellwerk liegt zum wesentlichen Teil als UML-Analyse bereits vor. Das ist reine Logik, keine Anzeige oder Bedienung.

Für eine gründliche Aufbereitung des GUI-Teils bietet sich ebenfalls ein UML-Modell an. Ich habe trotzdem schon mal ein wenig vorweg experimentiert, halt Bottom-Up, um auszuprobieren was geht, ohne Räder neu zu erfinden.

Eine der Entscheidungen beim Design wird sein, wo man aufsetzt, auf der leeren Zeichenfläche, oder vielleicht auf Basis-Steuerelementen. Ich habe Versuche mit letzterem gemacht, Plattform .Net und Windows-Forms.

So lassen sich Weichen/Signalhebel, Fahrstraßenhebel und Blockfelder durchaus als Buttons implementieren, auch wenn sie nicht wie Buttons aussehen. Man bekommt so direkt eine Menge Basis-Funktionalität, z.B. Visual Inheritance, um die neuen Controls mal eben zum Ausprobieren zusammenzuklicken, aber auch Unterstützung beim Layout mit automatischem Docking, wiederverwendbare Properties, aufbereitete Events mit lokalen Maus-Koordinaten usw. Natürlich sind die normalen Button-Zeichenfunktionen eher ungeeignet, aber der Zeichenaufwand für Owner-Drawn-Buttons hält sich in Grenzen. Die diversen Bitmaps dazu lassen sich in Resource-Files speichern, die Sounds leider nicht.

Für den Ton bietet sich die Audiowiedergabe aus Managed DirectX an, so wie sie auch Jens Haupert bei seinen Applikationen verwendet (das ist nicht Direct-Sound, sondern schlichtes Abspielen einer Audiodatei, wie wir es auch aus Win32 kennen.)

Die Attribute dieser neuen Controls werden im Wesentlichen über Properties gesetzt, auch der Anfangszustand, ggf bietet sich noch die eine oder andere explizite Funktion an, z.B. externes Entsperren eines Blockfeldes, wo es ja klappert oder rasselt. Auch die Bedienbarkeit, blockiert oder nicht, wird über Properties gesetzt, ähnlich dem klassischen Enable. Vom Bediener ausgelöste Zustandsänderungen werden über Events rückgemeldet.

Wie koppelt man nun die Bedienung mit der Logik?. Mir schweben im Moment Brückenobjekte auf GUI-Seite vor, die die Stellwerkslogik als abstrakte Interface-Klassen kennen, und die Bedienelemente als konkrete Member (Attribute/Felder) enthalten. Diese Brückenobjekte „kennen“ auch die Konfiguration, d.h. sie sind über IDs eindeutig ansprechbar. Ein solcher Weg über Brückenobjekte scheint mir ein geeigneter Kompromiss aus Vererbung und Delegation zu sein.

Verfasst: 14.07.2005 19:24:12
von Carsten Hölscher
in der Delphi-Welt könnte auch die Panel-Komponente für sowas ganz gut geeignet sein.

Carsten

Verfasst: 14.07.2005 21:06:29
von Roland Ziegler
Das Panel hatte ich mir bereits als sinnvollen Conatainer ausgeguckt. Damit werden alle neuen Controls automatisch richtig platziert.

Im Moment versuche ich gerade ein wenig über TypeConverter herauszufinden. Damit steuert Windows-Forms Property-Grids, die Formulare, in denen sich Properties zur Design-Zeit einstellen lassen. So etwas könnte für den angestrebten Stw-Editor von Interesse sein. Basiert massiv auf Reflection und wird zu einer Art Meta-Programmierung; die Theorie artet leider etwas aus. Sinnvoll nutzbar deshalb vermutlich nur dann, wenn nach Schema f anwendbar.

Verfasst: 14.07.2005 22:48:35
von Roland Ziegler
TypeConverter funktioniert. Hier am Beispiel eines Fahrstraßenhebels. Der hat eine bestimmte momentane Beweglichkeit in beiden Richtungen. Welche, gibt die Property Interlocking bzw Interlocking2 an. Diese Property kann man dann auch im Designer ändern, bzw man könnte eigene Designer schreiben, die diese setzen. Damit man überhaupt zur Designzeit darauf zugreifen kann, benötigt man besagte TypeConverter, die man jedoch jeweils selbst schreiben muss.

Bild

(TypeConverter sind nur eine kleine unwichtige Nebenepisode, es reizte mich einfach auszuprobieren, ob man Properties auch dann zur Designzeit setzen kann, wenn es keine Basistypen sind. Erschwerend kam hier noch hinzu, dass es sich um einen Value-Typ handelt, für den zur Neubesetzung das komplette Objekt konstruiert werden muss, mittels Reflection auf Meta-Ebene. Ist lustig, aber zeigt, was man alles mit .net anstellen kann.)

Code: Alles auswählen

      if ((destinationType == typeof(InstanceDescriptor)) && (value is Interlocking)) {
        Interlocking lock2 = (Interlocking) value;
        Type[] typeArray1 = new Type[2] { typeof(int), typeof(int) } ;
        ConstructorInfo info1 = typeof(Interlocking).GetConstructor(typeArray1);
        if (info1 != null) {
          object[] objArray1 = new object[2] { lock2.Lower, lock2.Upper } ;
          return new InstanceDescriptor(info1, objArray1);
        }
      }

Verfasst: 15.07.2005 08:37:32
von Oliver Lamm
Hmm ... also diese Grafikobjekte kommen mir seeehr bekannt vor :-)

SCNR Oli

Verfasst: 15.07.2005 08:55:41
von Roland Ziegler
Mit irgendwas muss man ja anfangen. Die Fahrstraßenhebel sind aber bereits neu gezeichnet, da habe ich noch ausprobiert, ob man den Entriegelungsgriff mit andeuten kann. Generell aber scheinen mir die pixelmäßigen Abmessungen jener Vorlagen schon ganz gut passend.

Aber letzlich sind die Bitmaps für die Entwicklung der Klassen Schall und Rauch. Ihre Größe bestimmt die Größe des Controls. Alle Bitmaps werden auf 32Bit gemappt (Meine Beispiele sind 8bit Indexd Gifs.) Zusätzliche Pixelpositionen von z.B. sensitiven Bereichen für die Schaltfläche wird pro Klasse vorgegeben. Ließe sich ggf später auch noch zur Laufzeit anpassbar machen.

Verfasst: 15.07.2005 17:18:00
von Carsten Hölscher
ich habe noch nicht so ganz das besondere daran kapiert. Zumindest bei Delphi (mit Win32) ist es kein Problem, Komponenten zur Designzeit komplett zu konfigurieren.

Carsten

Verfasst: 15.07.2005 17:44:30
von Roland Ziegler
Da ist auch nichts besonderes dran. Außer dass der Bereich aus der proprietären Ecke geholt und in den .Net-Standard integriert wurde - und in diesem Zusammenhang alle möglichen Basteleien aufgegeben und auf die Meta-Ebene (sprich: Reflection) verlegt wurden - für den Anwender wirkt es ähnlich, die Technik dahinter ist eine vollkommen andere.

Das war ja eine der Architekturen, die der Herr Hejlsberg aus seiner Borland-Zeit mit zu MS genommen hat, und so etwas lässt sich halt hervorragend in einer Meta-Landschaft unterbringen - wie sie aber eben nur Plattformen wie .Net oder Java bieten können.

Unter .Net ist es theoretisch vollkommen egal, mit welcher IDE man hier arbeitet - sämtliche Informationen für diese Komponenten - Designzeit und Laufzeit - stehen in genormtem Format in der Assembly, als Intermediate Language, für jedes Werkzeug zugänglich.

Verfasst: 17.07.2005 15:03:27
von Roland Ziegler
Jetzt mit neuen Bitmaps:

Bild

Verfasst: 18.07.2005 10:34:44
von Markus H.
Ich habe zwar keine Ahnung von Euren Programmen aber der kleine "Screenshot" gefällt mir schon einmal sehr sehr gut... da bekommt man Lust auf mehr.
Weiter so Junx echt super! :]

Kleiner Schönheitsfehler: Der Zeiger im Blockfeld kommt beim Original von rechts!

Gruß
Marcus

Verfasst: 13.08.2005 19:20:25
von Roland Ziegler
Allmählich wird es etwas konkreter.

Ich bastle, wie an anderer Stelle erwähnt, an einem animierbaren Lageplan, der bei mech und emech den noch nicht vorhandenen frei wählbaren Merhrbenutzer-Zusi-Stellwerksblick kompensiert, und der in ähnlicher Form bei SpDr- und EStw-Technik natürlich ebenfalls vorkommt.

Dazu existieren erste rudimentäre Ansätze eines Editors, und es existiert ein Datenformat, das erstaunlicherweise XML heißt.

Bild

Für die Serialisierung, also das Speichern auf File, benutze ich die XMLSerializer-Klasse aus .Net. Das Ding ist schon fein, erlaubt es doch ganze Objektbäume zu serialisieren, ohne dafür den üblichen Code schreiben zu müssen. Wie sowas funktionieren kann? Mittels Reflection!

Code: Alles auswählen

<?xml version="1.0" encoding="utf-8"?>
<Stellwerk xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.rolandziegler.de/Stellwerk">
  <Spurplan Typ="Stw.Anzeige.GridPanel">
    <Dim>
      <Width>20</Width>
      <Height>10</Height>
    </Dim>
    <Element Typ="Stw.Anzeige.GrenzeLinks" RefId="0" RefId2="0" Text="v. u. n." Text2="Adf">
      <Index>
        <X>0</X>
        <Y>7</Y>
      </Index>
      <Overlays Typ="Stw.Anzeige.Overlays" />
    </Element>
    <Element Typ="Stw.Anzeige.GeradeHorizontal" RefId="0" RefId2="0" Text="a">
      <Index>
        <X>1</X>
        <Y>7</Y>
      </Index>
      <Overlays Typ="Stw.Anzeige.Overlays">
        <Overlay Typ="Stw.Anzeige.Vorsignal" Signal="Dreibegriffig" Pos="FahrtrichtRechts_RechteSeite" RefId="0" />
      </Overlays>
    </Element>
...
Uns so sieht das in einer der beteiligten Klassen aus, wobie man die XML-Attributierung auch weglassen kann, hat hier nur kosmetische Bedeutung bezüglich der Benamsung:

Code: Alles auswählen

	public class GleiselementFields
	{
    [XmlAttribute (AttributeName = "Typ")]
    public string typeName;

    [XmlElement(ElementName = "Index")]
    public Point index;

    [XmlAttribute (AttributeName = "RefId")]
    public uint refId;
    
    [XmlAttribute (AttributeName = "RefId2")]
    public uint refId2;

    [XmlAttribute (AttributeName = "Text")]
    public string text;
    
    [XmlAttribute (AttributeName = "Text2")]
    public string text2;

    [XmlElement(ElementName = "Overlays")]
    public OverlaysFields overlaysFields;
...

Verfasst: 27.08.2005 15:56:21
von Roland Ziegler
Und noch ein Bildchen. Für die erste Komponente ist damit ein iteratives Inkrement (:D) erreicht.

Bild

Verfasst: 28.08.2005 15:47:02
von Michael_Poschmann
Moin Roland,

falls Du Pläne für einen netten Abzweigbahnhof benötigst oder aber Übergang E43/ mech - Fingerschnipps genügt. Mit Exoten testet es sich schließlich am besten... ;)

Bis später
Michael

Verfasst: 28.08.2005 16:03:01
von Roland Ziegler
Ich mach' nur Werkzeuge ... :looking:

Verfasst: 28.08.2005 20:58:11
von Gerd Schütz
Das sieht ja richtig Klasse aus. :wow

Gruß

Gerd

Verfasst: 27.09.2005 18:33:16
von Stellwerk-Stef
Wow! Deine Bilder sehen echt super aus! Gibts schon wieder was neues?
Ach ja falls du noch Bilder brauchst oder noch Fragen zur Technik hast brauchst du nur mit dem Finger schnippen ich wede dir gerne helfen!
MfG.Stefan
Edit: Werden auch BÜs simuliert?

Verfasst: 27.09.2005 21:46:14
von Roland Ziegler
Im Moment geht es um eher profane Dinge, wie Zuweisen der IDs zu Objekten zur Laufzeit, Anfangszustände beim Umschalten zu Zusi und dergleichen softwaretechnischen Kleinkram.

Bahnübergänge werden berücksichtigt.

Verfasst: 28.09.2005 07:54:50
von (Ar-) T-Rex
Zu den "profanen" Dingen gehörte eigentlich auch eine Ausrüstung mit Streckenblock (o je, eine eigene Wissenschaft, vor allem beim Felderblock!).

Hat man das auch schon angedacht?

Arthur

Verfasst: 28.09.2005 08:36:00
von Roland Ziegler
Man hat. Und auch der Bahnhofsblock spielt eine Rolle. Für diesen Themenbereich ist die Abbildung auf die interne Modellierung bei Zusi 3 von besonderem Interesse, da sie nicht 1:1 erfolgen kann.

Verfasst: 28.09.2005 08:55:56
von Hanspeter Thöni
Roland Ziegler hat geschrieben:Und noch ein Bildchen.
Das aussehen kommt mir aber sehr bekannt vor...

Könnte es sein, dass hier ein DB-Internes Progrämmchen vorbild gestanden hat?