Oberflächenentwicklung: Referenz

Inhaltsverzeichnis

3 Referenz

3.1 Basisklassen

3.1.1 VisualElement

In der (abstrakten) Basisklasse com.cisag.pgm. gui.VisualElement sind die gemeinsamen Methoden und Eigenschaften aller (visuellen) Elemente aus dem Package com.cisag.pgm.gui zusammengefasst. Alle Elemente, einschließlich der verschiedenen Containerarten, sind von dieser Klasse abgeleitet. Die wesentlichen Eigenschaften und Aufgaben von VisualElement sind im Abschnitt 2.1.3 VisualElement beschrieben.

3.1.1.1 Implementierung

Ein Großteil der eigentlichen Implementierung des UI-Frameworks erfolgt nicht in dem Package com.cisag.pgm.gui, sondern in dem Package com.cisag.pgm.dialog.

Jeder Instanz von com.cisag.pgm.gui.VisualElement ist zur Laufzeit (mindestens) eine Instanz von com.cisag.pgm.dialog.VisualElement zugeordnet.

Die Referenz auf die Instanz von com.cisag.pgm.dialog.VisualElement speichert das com.cisag.pgm.gui.VisualElement in einer Instanzvariablen mit dem Namen „x“. Deshalb wird in diesem Zuammenhang auch häufig von dem „X-Element“ gesprochen. Die Erzeugung (Instanziierung) des „X-Elements“ erfolgt jeweils durch die konkreten Elemente (Button, TextField, etc.), wobei der Erzeugungszeitpunkt von dem Elementtyp abhängig ist. Bei einigen Elementen wird das zugehörige „X-Element“ bereits im Konstruktor erzeugt, bei anderen (insbesondere Fields) erst beim Hinzufügen (add) zu einem Container[1]. Aufgrund dieser Tatsache sollten Elemente immer erst einem (ihrem) Container hinzugefügt werden, bevor irgendwelche Methoden an ihnen aufgerufen werden. Anderfalls kann es zu einer java.lang.NullPointer Exception kommen.

Die Beziehung von Element zu „X-Element“ findet sich auch bei allen abgeleiteten Klassen wieder, z. B. ist einem com.cisag.pgm.gui.Button zur Laufzeit ein com.cisag. pgm.dialog.Button zugeordnet.

Wobei com.cisag.pgm.gui.Button (zusätzlich zu der gleichnamigen Referenz in com.cisag.pgm.gui.Visual Element) ebenfalls eine eigene Instanzvariable mit dem Namen „x“ besitzt. Beide Referenzen zeigen zur Laufzeit auf dieselbe Instanz von com.cisag.pgm.dialog.Button. Diese Konstruktion dient dazu in den abgeleiteten Klassen ohne Cast-Operation auf klassenspezifische Methoden zugreifen zu können.[2]

3.1.1.2 VisualElement API

Die folgenden Tabellen zeigen die wichtigsten bzw. meistgenutzten Methoden von VisualElement (eine vollständige Liste bzw. detaillierte Beschreibungen sind in der JavaDoc-Dokumentation von VisualElement zu finden):

Tabelle 1: Visuelles Erscheinungsbild
Methode Verwendung
getBorder()

setBorder(Border)

Rahmen (Border) abfragen, setzen oder ändern (siehe 3.10.1 Border).
getMargin()

setMargin(Insets)

setMargin(int, int, int, int)

getInsets()

Randabstände (Margins/Insets) abfragen, setzen oder ändern (siehe 3.10.4 Insets).
getForeground()

setForeground(Color)

getBackgraound()

setBackground(Color)

Vordergrund- (Schrift-) bzw. Hintergrundabfragen, setzen oder ändern (siehe 3.10.3 Font und 3.10.6 UIManager).
getFont()

setFont(Font)

Schriftart, Schriftgröße und Schriftstil abfragen, setzen oder ändern (siehe 3.10.3 Font und 3.10.6 UIManager).
setTexture(Icon) Icon als Hintergrundmuster (Textur) setzen.

 

Tabelle 2: Allgemeiner Zustand
Methode Verwendung
isEnabled()

setEnabled(boolean)

Interaktivitätszustand (enabled/disabled) abfragen oder ändern.

Ein Element mit enabled==true reagiert auf Benutzeraktionen, ein Element mit enabled==false nicht.

isVisible()

setVisible(boolean)

Sichtbarkeit abfragen oder ändern.

„Unsichtbare“ Elemente werden auf dem Client nicht angezeigt. Je nach Layout-Manager wird der Platz auf dem Bildschirm „freigehalten“ oder durch andere Elemente belegt.

isEditable()

setEditable(boolean)

Editierbarkeit abfragen oder ändern.

Bei Eingabefeldern bestimmt diese Eigenschaft z. B., ob der angezeigte Text auch durch den Benutzer geändert (editiert) werden kann.

 

Tabelle 3: Metadatenunterstützung
Methode Verwendung
getAbsolutePath() Liefert den absoluten Pfad der zugehörigen Metadaten (Attribut, logischer Datentyp, …).
getRelativePath() Liefert den „hinteren“ Teil des Metadatenpfades (Attributname).
getReferencePath() Liefert den „vorderen“ Teil des Metadatenpfades (Namespace, Business Object).
setPath() Den relativen und absoluten Pfad für ein Element setzen oder berechnen.

Wird durch das Framework aufgerufen, entweder bereits im Konstruktor oder nachdem ein Element einem Container hinzugefügt wurde (addedToContainer()).

getToolTipText()

setToolTipText(String)

setToolTipTextFrom(
String)

setToolTipTextFrom(
String, Object[])

Text für ToolTip abfragen, setzen oder ändern.

Der spezifizierte Text wird angezeigt, wenn der Benutzer mit dem Mauszeiger über das Element „fährt“. Bei Elementen, die mithilfe von Metadaten (DataDescription, ActionDescription) erzeugt werden, wird dieser Wert automatisch vorbelegt.

getContextHelpID()

setContextHelpID(String)

Identifikation für Direkthilfe (F1) abfragen, setzen oder ändern.

Bei Elementen, die mithilfe von Metadaten (DataDescription, ActionDescription) erzeugt werden, wird dieser Wert automatisch vorbelegt.

isRequired()

setRequired(boolean)

Prüfen bzw. Festlegen, ob es sich bei dem Element um ein sog. Pfichtfeld handelt.

Bei Elementen, die mithilfemithilfe von Metadaten (DataDescription) erzeugt werden, wird dieser Wert automatisch vorbelegt.

 

Tabelle 4: Ereignisbehandlung
Methode Verwendung
getDoubleClickAction()

setDoubleClickAction(
Action)

Aktuelle „Doppelklick-Action“ abfragen bzw. neue Action registrieren.

Die registrierte Action wird ausgelöst, wenn der Benutzer einen Doppelklick das Element macht.

getLinkAction()

setLinkAction(Action)

Aktuelle „Link-Action“ abfragen bzw. neue Action registrieren.

Die registrierte Action wird ausgelöst, wenn der Benutzer mit der linken Maustaste auf das Element klickt. Im Allgemeinen implementiert die Action eine Art Hyperlink.

getPopupAction()

setPopupAction(Action)

Aktuelle „Popup-Action“ abfragen bzw. neue Action registrieren.

Die registrierte Action wird ausgelöst, wenn der Benutzer z. B. mit der rechten Maustaste auf das Element klickt. Im Allgemeinen implementiert die Action das Öffnen eines Popup-Menüs (siehe 3.8.4 PopupMenu).

getObjectType()

setObjectType(String)

Aktuellen Objekttyp abfragen bzw. neuen Objekttyp setzen.

Der Objekttyp dient zur Klassifizierung von Elementen bzw. der darin dargestellten Daten. Über den Objekttyp werden z. B. das zugehörige Kontextmenü oder die möglichen Drag & Drop-Aktionen bestimmt.

registerKeyStroke(Action)

registerKeystroke(
Action[])

registerKeyStroke(
String,Action)

deregisterKeystroke(
Action)

deregisterKeystroke(
Action[])

deregisterKeystroke(
String, Action)

Registrieren oder Deregistrieren von Actions für bestimmte Tasten bzw. Tastenkombinationen (key strokes).

Typischerweise geschieht es automatisch und die Tastenkombinationen sind im Repository (Entwicklungsobjekt „Action“) hinterlegt.

getActionsAsArray() Liefert alle intern definierten (Sub)Actions zurück.

 

Tabelle 5: Fokussteuerung
Methode Verwendung
hasFocus() Prüft, ob das aktuelle Element den Tastaturfokus besitzt.
requestFocus() Mit dieser Methode kann der Wechsel des Tastaturfokus programm- bzw. serverseitig angefordert werden.
isFocusTraversable()

setFocusTraversable(
boolean)

Prüfen bzw. Festlegen, ob das aktuelle Element per „TAB“ den Tastaturfokus bekommen kann bzw. „übersprungen“ wird.

Hinweis:
Trotz „focusTraversable == false“ kann der Benutzer dem Element noch per Mausklick den Tastaturfokus geben (siehe setRequestFocusEnabled()).

isRequestFocusEnabled()

setRequestFocusEnabled(
boolean)

Prüfen bzw. Festlegen, ob das aktuelle Element per requestFocus() den Tastaturfokus bekommen kann.

Hinweis:
„requestFocusEnabled==false“ verhindert auch, dass der Benutzer dem Element per Mausklick den Tastaturfokus geben kann.

isFocusCycleRoot() Prüft, ob es sich bei dem Element um einen Container mit zyklischem Tastaturfokus handelt, d. h. bei TAB und Shift+TAB wechselt der Tastaturfokus nur innerhalb der Subelemente.

Um das Element zu verlassen, muss der Benutzer CTRL+G bzw. CTRL+SHIFT+G drücken. Diese Eigenschaft wird nur von bestimmten Containern implementiert und lässt sich nicht ändern.

focusElementWith(
VisualElement,String)
Veranlasst, den Client nach dem Drücken der spezifizierten Tastenkombination durch den Benutzer automatisch den Eingabefokus auf das spezifizierte Element zu wechseln.

Mit Hilfe dieser Methode kann der Tastaturbuffer auf dem Client besser ausgenutzt und so das Eingabeverhalten verbessert werden.

 

Tabelle 6: Meldungen
Methode Verwendung
registerMessage(int)

registerMessage(int[])

registerMessage(String, int[])

Verbindet das Element (Feld) mit einer oder mehreren Meldungen (IDs) (siehe 2.1.7 Meldungen).
requiresAttention() Prüft, ob für das Element Fehlermeldungen oder unbestätigte Warnungen vorliegen.

 

Tabelle 7: Container-Hierarchie
Methode Verwendung
getParent() Liefert das übergeordnete Container-Element zurück, d. h. den VisualElementContainer, dem dieses Element mit add hinzugefügt wurde.
addedToContainer(
VisualElementContainer, Object)
„Notifier“- bzw. „Hook“-Methode.

Wird durch das Framework aufgerufen, wenn ein Element einem Container hinzugefügt wurde.

getWindow() Verfolgt die Container-Hierarchie des aktuellen Elements bis zu dem „Top-Level“-Container (Window) und gibt diesen zurück.
isAncestor(VisualElement) Prüft, ob es sich bei dem spezifizierten Element um einen direkten oder indirekten „Eltern“-Container des aktuellen Elements handelt.

 

Tabelle 8: Layout-Unterstützung
Methode Verwendung
getAlignmentX()

setAlignmentX(float)

getAlignmentY()

setAlignmentY(float)

Horizontale und vertikale Ausrichtung (relativ zu den anderen Elementen im Container) abfragen, setzen oder ändern (siehe 2.1.2.2 Hinweise für den Layout-Manager, 3.9.3 BoxLayout).
getPreferredWidth()

setPreferredWidth(int)

getPreferredHeight()

setPreferredHeight(int)

Bevorzugte (optimale) Breite und Höhe abfragen, setzen oder ändern (siehe 2.1.2.2 Hinweise für den Layout-Manager).

Die meisten Elemente berechnen ihre bevorzugte Größe automatisch (unter Berücksichtigung von Schriftgröße, Bildschirmauflösung). Das ist gleichermaßen gültig für einen Label als auch für einen komplexen Container.

getMinimumWidth()

setMinimumWidth(int)

getMinimumHeight()

setMinimumHeight(int)

Minimale Breite und Höhe abfragen, setzen oder ändern.

Dient als Hinweis für den Layout-Manager und spezifiziert, wie weit das Element verkleinert werden darf (siehe 2.1.2.2 Hinweise für den Layout-Manager).

getMaximumWidth()

setMaximumWidth(int)

getMaximumHeight()

setMaximumHeight(int)

Maximale Breite und Höhe abfragen, setzen oder ändern.

Dient als Hinweis für den Layout-Manager und spezifiziert, wie weit das Element vergrößert werden darf (siehe 2.1.2.2 Hinweise für den Layout-Manager).

Methode Verwendung
getDataColumnSupport()

setDataColumnSupport(
DataColumnSupport

Informationen für den Datenexport (siehe 3.6.1.4 Datenexport) abfragen, setzen oder ändern.
createDataColumnSupport() Subklassen können diese Methode überschreiben um angepasste Informationen für den Datenexport zu liefern.

 

3.1.2 VisualElementContainer

Die Klasse com.cisag.pgm.gui.VisualElementContainer erweitert com.cisag.pgm.gui.VisualElement um typische Containereigenschaften, d. h. ein VisualElementContainer kann andere Objekte vom Typ VisualElement aufnehmen. Da VisualElementContainer selbst ein VisualElement ist, lassen sich so beliebige Hierarchien von Elementen bzw. Containern bilden (siehe 2.1.1 Elemente und Container-Hierarchie).

VisualElementContainer ist die (abstrakte) Basisklasse für alle Container-Implementierungen. Dazu zählen die Hilfs-Container wie z. B. com.cisag.pgm.gui.View als auch die Top-Level Container wie z. B. com.cisag.pgm.gui.Dialog (siehe 2.1.1 Elemente und Container-Hierarchie).

Wobei die Top-Level Container nicht direkt von VisualElementContainer erben, sondern von com.cisag.pgm.gui.Window (die Basisklasse für alle Top-Level Container, siehe 3.1.3 Window).

Die Platzierung seiner Elemente delegiert der Container an den ihm zugeordneten Layout-Manager (siehe 2.1.2 Layout-Management, 3.9 Layout-Manager). Die Zuordnung eines Layout-Managers mit setLayout() muss in der Regel vor dem Hinzufügen von Elementen erfolgen.

3.1.2.1 VisualElementContainer API

Die folgenden Tabellen zeigen die wichtigsten bzw. meistgenutzten Methoden von VisualElementContainer (eine vollständige Liste bzw. detaillierte Beschreibungen sind in der JavaDoc-Dokumentation von VisualElementContai-ner zu finden:

Tabelle 10: Visuelles Erscheinungsbild
Methode Verwendung
INSETS_NONE

INSETS_TOP

INSETS_BOTTOM

INSETS_LEFT

INSETS_RIGHT

INSETS_ALL

setDefaultMargin(int)

Setzen der Standardrandabstände (siehe 3.10.4 Insets).

 

Tabelle 11: Anwendungsunterstützung
Methode Verwendung
isSelectionView()

setSelectionView(boolean)

Prüfen oder Festlegen, ob alle (ab dem Zeitpunkt der Festlegung) mit add hinzugefügten Felder automatisch in den Selektionsmodus geschaltet werden sollen.
getObjectReference()

setObjectReference(
byte[])

Erlaubt die Assoziation zwischen einem Container und einer Objektreferenz.

 

Tabelle 12: Fokussteuerung
Methode Verwendung
setDefaultFocus(
VisualElement)
Legt fest, an welches Subelement der Tastaturfokus weitergegeben werden soll, falls der Container den Tasturfokus erhalten sollte.

 

Tabelle 13: Container-Hierarchie
Methode Verwendung
add(VisualElement)

add(VisualElement,int)

add(VisualElement,Object)

add(VisualElement,
Object, int)

Fügt dem Container das spezifizierte Element hinzu.

Optional kann die Position (Index) angegeben werden, an der das neue Element eingefügt werden soll. Einige Layout-Manager benötigen zusätzliche Angaben für die Platzierung des neuen Elements. In diesem Fall ist als zusätzlicher Parameter ein „Contraints“-Objekt zu übergeben (siehe 2.1.2 Layout-Management, 3.9 Layout-Manager)

remove(VisualElement)

removeAll()

Entfernen von einzelnen oder allen Subelementen.
contains(VisualElement) Prüfen, ob ein bestimmtes Element in dem Container oder in einem seiner Subelemente liegt (rekursiv).

 

Tabelle 14: Layout-Unterstützung
Methode Verwendung
setLayout(LayoutManager) Ordnet dem Container den spezifizierten Layout-Manager zu (siehe 2.1.2 Layout-Management, 3.9 Layout-Manager).
setGuides(int)

setGuides(int, boolean)

setGuides(double[], double[], double[], double[])

Definiert Führungslinien für diesen und alle untergeordneten Container. Die Führungslinien werden von allen Containern mit StandardLayout genutzt, um ihre Element daran auszurichten. In der einfachsten Form, ist nur die gewünschte Anzahl von Spalten anzugeben (alle Spalten bekommen die gleiche Breite).

Die Möglichkeit Führungslinien über die Konstruktoren der Klasse StandardLayout zu definieren gilt als „deprecated“. Die hier beschriebenen Methoden haben den Vorteil, dass die Definition von Führungslinien unabhhängig von der Verwendung eines StandardLayouts erfolgen kann. Damit wird es einfacher, die Führungslinien nur einmal und bereits auf der höchstmöglichen Containerebene zu definieren.

removeAllGuides() Entfernt alle (direkt) für diesen Container definierten Führungslinien.

 

3.1.3 Window

Die Klasse com.cisag.pgm.gui.Window erweitert com.cisag.pgm.gui.VisualElementContainer um zusätzliche Eigenschaften für „Top-Level“-Container. Wie bei VisualElement und VisualElementContainer, handelt es sich auch bei dieser Klasse um eine abstrakte Basisklasse. Anders als die meisten Container, haben alle von Window abgeleiteten Klassen bereits bei ihrer Erzeugung mindestens ein Subelement[3]. Die Top-Level Container nutzen diese Elemente für ihre eigene Implementierung, daher sollten bei Top-Level Containern nie Elemente direkt mit add/remove hinzugefügt oder entfernt werden. Für den generellen Zugriff stellen Windows stattdessen ihr sogenanntes „Content-Pane“ zur Verfügung. Dabei handelt es sich um einen Subcontainer des Windows, den man sich mit getContentPane() vom Window liefern lassen kann. Dieser Container kann wie jeder andere Container verwendet werden. Das Content-Pane kann auch mit setContentPane() ausgetauscht werden, jedoch wird das nicht empfohlen, dadurch können verschiedene Defaulteinstellungen (Look & Feel, Tastatur, Fokussteuerung) verloren gehen.

3.1.3.1 Window API

Die folgenden Tabellen zeigen die wichtigsten bzw. meistgenutzten Methoden von Window (eine vollständige Liste bzw. detaillierte Beschreibungen sind in der JavaDoc-Dokumentation von Window zu finden):

Tabelle 15: Ereignisbehandlung
Methode Verwendung
setClosedAction(Action) Action für „window closed“ registrieren.

Die registrierte Action wird ausgelöst, wenn das Fenster geschlossen wurde.

addRefreshListener(
RefreshListener)

removeRefreshListener(
RefreshListener)

Registrierung bzw. Deregistrierung eines EventListeners für Client-Aktualisierungen.

Erlaubt die Aktualisierung des Clients in regelmäßigen Intervallen (siehe getRefreshInterval()).

Warnung:
Die Verwendung dieser Methoden kann die Funktion der Client/Server-Kommunikation stark beeinträchtigen.

getRefreshInterval()

setRefreshInterval(int)

Akualisierungsintervall abfragen bzw. ändern.

Warnung:
Der Standardwert stellt einen guten Kompromiss zwischen Aktualisierungsfrequenz und Systembelastung dar und sollte nicht geändert werden. Eine Änderung des Wertes kann die Funktion der Client/Server-Kommunikation stark beeinträchtigen.

isKeyStrokeSupported(
String)
Prüft, ob eine bestimmte Taste bzw. Tastenkombination (key stroke) durch den Client bzw. den aktuellen Client-Modus unterstützt wird.

 

Tabelle 16: Fokussteuerung
Methode Verwendung
getFocusOwner() Liefert das Subelement zurück, welches aktuell den Tastaturfokus besitzt.

 

Tabelle 17: Container-Hierarchie
Methode Verwendung
getContentPane()

setContentPane(View)

Liefert das „Content-Pane“ des Fensters zurück bzw. tauscht es aus.
getOwnedWindows() Liefert ein Array mit allen, vom aktuellen Fenster abhängigen, Fenstern zurück.

 

3.1.4 Field

com.cisag.pgm.gui.Field ist die (abstrakte) Basisklasse für alle Elemente, die der Ein- und Ausgabe von Daten dienen. Dazu zählen einfache Textfelder, als auch Check- und Comboboxen. Die Klasse Field erweitert dazu die Elternklasse com.cisag.pgm.gui.VisualElement um folgende Eigenschaften:

  • Label
  • einen Wert (Value)
  • Initialisierung über Metadaten (DataDescription)
  • verschiedene Indikatoren und optionale Interaktionselemente
  • spezielle Unterstützung für Tabellen (Factory für „Zelleditoren“)

3.1.4.1 Generelle Eigenschaften

Label

Ein Feld besteht grundsätzlich aus zwei Teilen. Im Hauptteil wird der aktuelle Wert (Daten) angezeigt bzw. kann dort vom Benutzer eingegeben oder geändert werden. Der zweite Teil (Label) dient als Beschreibung (Beschriftung) für das Feld und hilft dem Benutzer verschiedene Felder zu unterscheiden bzw. einzelne Felder zu identifizieren. Dieser Teil ist jedoch optional, d. h. in bestimmten Anwendungsfällen (z. B. in Tabellen und Listen) kann das Label unterdrückt werden.

  • Feld mit links platziertem Label
  • Felder ohne eigenen Label (Verwendung in Listen)
Daten und Datentypen

Felder dienen der Eingabe und Ausgabe von „Daten“. Auf dem Bildschirm werden die Daten zwar häufig als Text dargestellt, programmintern wird jedoch, je nach Datentyp (z. B. Text, Datum, Betrag,…), eine entsprechende Java-Klasse verwendet. Den Feldern fällt somit auch die Rolle zu, die internen Datentypen benutzergerecht aufzubereiten bzw. Benutzereingaben in die intern verwendeten Datentypen zu wandeln. Aus diesem Grund steht für jeden Datentyp eine abgeleitete Klasse von Field zur Verfügung, die diese Aufgabe erfüllt. Beispiele hierfür sind:

  • TextField (lang.String)
  • CisDateField (cisag.pgm.datatype.CisDate)
  • DecimalField (cisag.pgm.datatype.CisDecimal)
  • BooleanField (boolean)

Jede konkrete Subklasse besitzt (als Konvention) die Methoden getValue() und setValue(), deren Signaturen (Datentyp für Rückgabe- bzw. Parameterwerte) auf dem Datentyp des jeweiligen Feldes basieren. Ein TextField verwendet z. B. die Signaturen:

public String getValue()

public void setValue(String)

Ein CisDateField verwendet hingegen die Signaturen:

public CisDate getValue()

public void setValue(CisDate)

Auf der Ebene der konkreten Subklassen ist somit der typsichere Zugriff auf den Wert eines Feldes möglich. Zusätzlich bietet die Basisklasse Field auch den generischen Zugriff (mit java.lang.Object als Datentyp) über die folgende Methoden an:

public Object getValueAsObject()

public void setValueFromObject(Object)

DataDescription

Typischerweise erfolgt das Instanziieren von Feldern unter Bezug auf Metadaten aus dem Semiramis Repository. Hierzu wird beim Aufruf des entsprechenden Kontruktors ein „Pfad“ übergeben. Dieser Pfad kann sowohl absolut (inklusive Angabe von Namespace) als auch relativ sein (nur Attributname, erst durch den Container ergibt sich der absolute Pfad). Der Pfad identifiziert entweder ein Attribut eines Business Objects oder einen logischen Datentyp.

Wenn das Feld einem Container hinzugefügt wird, erfolgt automatisch die Ermittlung der zugehörigen DataDescription. Die DataDescription wird durch eine Instanz von com.cisag.pgm.dialog.model.DataDescription repräsentiert und stellt praktisch alle für Felder relevanten Metadaten bereit. Hierzu zählen insbesondere:

  • Datentyp
  • Label (inkl. Access-Key)
  • ToolTip
  • Direkthilfe
  • Beschränkungen für Inhalt (Länge, Wertebereich)
  • Angaben über Editierbarkeit, Pfichtfelder
  • Formatierung
  • Suche (Wertehilfe)

Die entsprechenden Eigenschaften des Feldes werden mit den Werten aus der DataDescription vorbelegt. Einige dieser Eigenschaften (siehe 3.1.4.2 Field API lassen sich nachträglich ändern.

Feldzustände und Eingabebereitschaft

Die in der Elternklasse definierten Eigenschaften enabled, editable und required (Pflichtfeld) werden bei Feldern aus der DataDescription initialisiert und können ggf. während der Laufzeit über die entsprechenden „set“-Methoden geändert werden. Die Visualisierung dieser Eigenschaften erfolgt über die Farben für Hintergrund und/oder Schrift bzw. über eine kleine graue Ecke rechts oben im Feld.

  • Nicht edititierbares Feld (editable==false)
  • Feld mit enabled==false
  • Pflichtfeld (required==true)
Wertehilfe

Felder können dem Benutzer eine Wertehilfe anbieten. Wertehilfen erleichtern dem Benutzer die Auswahl (Suche) bzw. Eingabe des gewünschten Wertes. Wertehilfen können als Dialog, Popup oder ComboBox bereitgestellt werden. Abhängig von der Art der Werthilfe, wird deren Verfügbarkeit durch ein kleines Dialogsymbol (rechte untere Ecke) oder einen ComboBox-Button visualisiert.

  • Feld für Artikelidentifikation (EntityField) mit Wertehilfe

In einigen Fällen wird die Wertehilfe vom UI-Framework automatisch bereitgestellt. So wird z. B. bei allen Datumsfeldern ein Kalender oder bei allen EnitityFields eine Standardsuche angeboten.

Es besteht auch die Möglichkeit eigene Wertehilfen zu implementieren. Eine solche Wertehilfe muss die abstrakte Klasse com.cisag.pgm.objsearch.SearchManager erweitern (siehe Dokument Programmierhandbuch).

Selektionsmodus

In einigen Anwendungsfällen, inbesondere bei Suchen und Abfrageanwendungen, ist es notwendig eine Liste von Werten, einen Wertebereich (Intervall) und/oder ein Suchmuster (mit Platzhaltern „*“, „?“) eingeben zu können. Im Dokument Bedienungsleitfaden werden die dafür genutzen Felder als „mehrwertige Eingabefelder“ bezeichnet.

Auf der Ebene der Implementierung werden teilweise spezielle Feldtypen bereitgestellt (siehe 3.5.23 Selektionsfelder), teilweise werden aber auch nur die üblichen Standardtypen verwendet, die nur in einen besonderen Modus versetzt werden müssen. Die notwendige Eigenschaft (selectionMode) ist auf der Ebene der Basisklasse definiert und wird je nach konkreter Subklasse unterschiedlich implementiert. Insbesondere EntityFields und ValueSetFields unterstützen diese Eigenschaft. Es gibt auch Feldtypen, die diese Eigenschaft nicht unterstützen.

Einige Felder zeigen den Selektionmodus durch einen kleinen Doppelpfeil (Button) im Labelbereich an. Bei Klick auf diesen Button wird ein Popup-Fenster geöffnet, aus dem der Benutzer vorgefertigte Selektionsmuster übernehmen kann.

  • EnitityField im Selektionsmodus
Dialog-Button

In den Labelbereich kann ein zusätzlicher Button eingefügt werden. Dieser Button wird in der Regel dann benutzt, wenn die direkte oder die vollständige Bearbeitung der Daten in dem Feld selbst nicht möglich ist und für die (zusätzliche) Bearbeitung ein Dialog bzw. Popup-Window verwendet werden soll. Im Dokument Bedienungsleitfaden wird dieser Button wegen seines Aussehens als „Rauten-Button“ bezeichnet. Im API wird er (wegen der üblichen Funktion) als „Dialog-Button“ bezeichnet.

Die Basisklasse Field bietet als Unterstützung nur die Möglichkeit eine sog. „Dialog-Action“ zu registrieren. Wenn eine solche Action registriert wurde, dann erscheint automatisch der „Rauten-Button“ im Labelbereich des Feldes. Wenn der Benutzer auf den Button klickt, wird die Action ausgelöst. Es liegt in der Zuständigkeit des Programmierers, bei dieser Action einen ActionListener zu registrieren und in dessen actionPerform()-Methode etwas „Sinnvolles“ zu tun. Aus Gründen der Einheitlichkeit (Erwartungskonformität) sollte das immer das Öffnen eines Dialoges bzw. Popup-Windows sein, obgleich es technisch nicht vorgegeben ist.

  • Feld mit „Rauten-Button“

Ein Beispiel für die Verwendung von Dialog-Buttons ist in Kapitel 4.3 Dialoge verwenden zu finden.

Hinweis:
Wenn es sich um ein mehrsprachiges Textfeld (d. h. mit NLS-Support) handelt, dann wird die Position und die Funktionalität des Dialog-Buttons für die Eingabe der Übersetzungen benötigt.

Ungültige Werte

Die konkreten Subklassen von Field sind jeweils für einen bestimmte Datentyp ausgelegt. So dient ein CisDateField z. B. dazu, Objekte vom Typ com.cisag.pgm.datatype.CisDate anzuzeigen bzw. vom Benutzer eingeben/bearbeiten zu lassen. Wenn die Eingabe des Benutzers nicht in diesen Datentyp umgewandelt werden kann (Syntaxfehler, ungültige Zeichen, etc.), so kann bei getValue() auch kein „gültiges“ Objekt des entsprechenden Datentyps zurückgeliefert werden.

Es gibt die Methode isValueValid(), die anzeigt, dass der eingegebene Wert nicht in ein entsprechendes Objekt gewandelt werden konnte. Jedoch hilft diese Methode leider nicht bei dem üblichen Programmiermodell[4], insbesondere weil die Prüf- und Logikklassen unabhängig von den UI-Klassen sein müssen, und deshalb nicht direkt auf deren Methoden zugreifen dürfen. Alle Felder mit nicht primitiven Datentypen liefern daher bei getValue() (und getValueAsObject()) spezielle Werte zurück. Diese Werte können bei dataFromUI() direkt in das zugehörige Business Object übernommen werden und werden von den Prüf- und Logikklassen in der Regel so behandelt, als ob der Benutzer das Feld leer gelassen hätte[5]. Zusätzlich registrieren die Felder die bei getValue() zurückgegebene Objektinstanz zusammen mit der (ungültigen) Benutzereingabe. Wenn zu einem späteren Zeitunkt setValue() (oder setValueAsObject()) aufgerufen wird, so wird geprüft, ob das übergebene Objekt zuvor als „ungültig“ registriert wurde. Wenn ja, wird im Feld wieder die ursprüngliche (ungültige) Benutzereingabe angezeigt.

3.1.4.2 Field API

Die folgenden Tabellen zeigen die wichtigsten bzw. meistgenutzten Methoden von Field (eine vollständige Liste bzw. detaillierte Beschreibungen sind in der JavaDoc-Dokumentation von Field zu finden):

Tabelle 18: Visuelles Erscheinungsbild
Methode Verwendung
getHorizontalAlignment()

setHorizontalAlignment(
int)

Textausrichtung innerhalb des Feldes abfragen, setzen oder ändern (Field.LEFT, Field.CENTER und Field.RIGHT).
getLabelPosition()

setLabelPosition(int)

Relative Position des Labels bezüglich des Wertes abfragen, setzen oder ändern. Unterstützt werden: „Label links neben dem Wert“ (Field.LABEL_LEFT) und „Label über dem Wert“ (Field.LABEL_TOP)

 

Tabelle 19: Datenzugriff
Methode Verwendung
getValueAsObject()

setValueFromObject(
Object)

Aktuellen Wert des Feldes abfragen oder ändern.

Diese, auf java.lang.Object basierenden, Methoden erlauben den generischen Datenzugriff bei allen Feldtypen. Die Subklassen von Field stellen zusätzlich jeweils die Methoden getValue() und setValue() bereit, wobei die Rückgabewerte bzw. Parameter dieser Methoden auf dem Datentyp des jeweiligen Feldes basieren.

getStringValue()

setStringValue(String)

Aktuellen Wert des Feldes abfragen oder ändern.

Diese, auf java.lang.String basierenden, Methoden erlauben den generischen Datenzugriff bei allen Feldtypen. Anders, als bei getValueAsObject() bzw. setValueAsObject() handelt es sich jedoch nur um eine Textrepräsentation des Wertes.

Hinweis:
Die Subklassen verwenden teilweise unterschiedliche Verfahren, um ihren Wert als Text zu formatieren bzw. um aus einem Text ein zum Datentyp passendes Objekt zu erzeugen.

isValueValid() Abfragen, ob der aktuelle Wert „gültig“ ist (siehe Abschnitt Ungültige Werte).

 

Tabelle 20: Anwendungsunterstützung
Methode Verwendung
getDialogAction()

setDialogAction(Action)

Aktuelle „Dialog-Action“ abfragen bzw. neue Action registrieren.

Die registrierte Action wird ausgelöst, wenn der Benutzer auf das Dialogsymbol (Raute) klickt.

setDialogActionEnabled(
boolean)
„enabled“-Zustand des Dialog-Buttons festlegen oder ändern.
setDialogButton(boolean) Sichtbarkeit des Dialog-Buttons festlegen oder ändern.
setSearchManager(
SearchManager)
Verwendung einer (alternativen) Wertehilfe.

Viele Subklassen besitzen bereits eine Standardwertehilfe (z. B. Kalender bei Datumsfeldern) bzw. sind über die Metadaten mit einer entsprechenden Suche verbunden. Mit der Bereitstellung einer eigenen SearchManager-Implementierung können spezielle Wertehilfen eingebunden werden.

setIndicator(Icon, String, int, int) Zusätzliches Icon in das Feld (oder Label) einfügen.

Ein solches Icon kann als Indikator für bestimmte Zustände oder Modi dienen.

Hinweis:
Diese Funktion wird teilweise schon für Standardaufgaben, z. B. mehrwertige Felder (Icon: Doppelpfeil) benutzt.

getObjectReference()

setObjectReference(
byte[])

Erlaubt die Assoziation zwischen einem Feld und einer Objektreferenz.

Wenn dem Feld keine Objektreferenz zugeordnet ist, wird bei getObjectReference() die beim (direkten) Elterncontainer hinterlegte Objektreferenz zurückgeliefert.

 

Tabelle 21: Unterstützung für Selektionsmodus
Methode Verwendung
isSelectionMode()

setSelectionMode(boolean)

Prüfen oder Festlegen, ob das Feld im Selektionsmodus arbeiten soll.

Die meisten Felder verhalten sich im Selektionsmodus wie Textfelder und der Benutzer kann in diese Felder (mehrwertige) Ausdrücke und Intervalle eingeben. Der Selektionsmodus wird jedoch nicht von allen Subklassen unterstützt.

getSelectionString() Liefert den vom Benutzer eingegebenen Selektionsausdruck.

 

Tabelle 22: Metadatenunterstützung
Methode Verwendung
getLabel()

setLabel(String)

setLabelFrom(String)

setLabelFrom(String, String[])

Text für Label abfragen, setzen oder ändern.

Bei Elementen, die mithilfe von Metadaten (DataDescription) erzeugt werden, wird dieser Wert automatisch vorbelegt. Wenn kein Label erwünscht ist, wie z. B. in Tabellen, kann das Label mit setLabel(null) unterdrückt werden.

getColumns()

setColumns(int)

Bevorzugte Breite des Eingabeteils abfragen oder ändern.

Aus der spezifizierten Anzahl von Zeichen, ermittelt das Feld automatisch die (Schrift- und auflösungsabhängige) „preferredWidth“. Der Wert -1 legt fest, dass sich „preferredWidth“ immer (dynamisch) nach dem aktuellen Inhalt des Feldes richten soll. Bei Feldern, die mithilfe von Metadaten (DataDescription) erzeugt werden, wird dieser Wert automatisch vorbelegt. Einige Subklassen von Field berechnen ihre „preferredWidth“ jedoch unabhängig von den bei „columns“ gesetzten Werten.

getOriginalPath() Liefert den Pfad so zurück, wie er im Konstruktor übergeben wurde. Demgegenüber liefert die Methode „getPath()“ nach „add“ den vollständigen Pfad.
setPath() Nicht zulässig, der Pfad für die Metadaten muss im Konstruktor übergeben werden.

 

Tabelle 23: Layout-Unterstützung
Methode Verwendung
getPreferredLabelWidth()

setPreferredLabelWidth(
int)

Bevorzugte (optimale) Breite für den Labelteil des Feldes abfragen, setzen oder ändern.

Diese Methode wird für einige Layout-Manager benötigt und sollte nicht direkt aufgerufen werden.

getLabelWidth()

setLabelWidth(int)

Breite für den Labelteil des Feldes abfragen, setzen oder ändern.

Diese Methode wird für einige Layout-Manager benötigt und sollte nicht direkt aufgerufen werden.

 

Tabelle 24: Implementierung
Methode Verwendung
createUiField() Erzeugung des „X-Elements“.

Subklassen von com.cisag.pgm.gui.Field müssen diese Methode überschreiben und können darin ihr „X-Element“ erzeugen und initialisieren. Dieses Methode wird durch das UI-Framework aufgerufen, wenn das Feld einem Container hinzugefügt wurde (aus addedToContainer())

setUiElement(
com..pgm.dialog.Field)
Registriert und initialisiert das übergebene „X-Element“ (ruft auch super.setUiElement() auf).

Subklassen müssen diese Methode in ihrer Implementierung von createUiField() aufrufen. Wenn diese Methode von Subklassen überschrieben wird, dann muss darin ebenfalls super.setUiElement() aufgerufen werden. Das Überschreiben dieser Methode ist notwendig, wenn die Subklasse eine eigene Referenz (Instanzvariable) auf das X-Element implementiert.

createTableEditor() Neue Instanz von com.cisag.pgm.dialog. Field erzeugen und für die Verwendung als Zelleditor in einer Tabelle konfigurieren.

Diese Methode wird durch die Implementierung der Tabelle aufgerufen. Subklassen von Field müssen diese Methode in der Regel immer dann überschreiben, wenn sie intern eine spezielle Implementierung für das „X-Element“ verwenden.

copyFromUiField(
com..pgm.dialog.Field)

copyToUiField(
com..pgm.dialog.Field)

Datenaustauch mit Zelleditoren.

Bei copyFromUiField wird der Wert aus dem Zelleditor in das Feld und bei copyToUiField aus dem Feld in den Zelleditor übernommen. Diese Methoden werden durch die Implementierung der Tabelle aufgerufen. Subklassen von Field müssen diese Methoden in der Regel immer dann überschreiben, wenn sie intern eine spezielle Implementierung für das „X-Element“ verwenden.

createInvalidValue() Erzeugen eines „ungültigen“ Wertes (siehe  Ungültige Werte).
getInvalidKeyFor() Liefert einen Schlüssel für die Registrierung von ungültigen Werten bei der zentralen Registrierungsstelle (InvalidValue Support).

Diese Methode wird intern verwendet und sollte nicht direkt aufgerufen werden.

getInvalidStringFor(
Object)
Liefert die ursprüngliche (fehlerhafte) Benutzereingabe zurück, die mit dem übergebenen Objekt assoziiert ist.

Diese Methode wird intern verwendet und sollte nicht direkt aufgerufen werden.

putInvalidStringFor(
Object, String)
Registriert den spezifizierten Wert zusammen mit dem spezifizierten fehlerhaften Text (Benutzereingabe) bei der zentralen Registrierungsstelle (InvalidValueSupport).

Diese Methode wird intern verwendet und sollte nicht direkt aufgerufen werden.

registerFieldMessages()

registerFieldMessages(
VisualElement ve)

Tatsächliche Registrierung aller zuvor mit registerMessage „registrierten“ Meldungen (IDs).

Diese Methode wird durch das UI-Framework aufgerufen, wenn das Feld einem Container hinzugefügt wurde (aus addedToContainer ()). Ein direkter Aufruf ist nicht zulässig.

createDataColumnSupport() Stellt eine generische Implementierung für den Datenexport bereit, die den Feldinhalt als String ausgibt.

Subklassen sollten diese Methode überschreiben, wenn sie eine speziellere Implementierung benötigen.

 

3.2 Top-Level Container

Die Top-Level Container stellen jeweils die Wurzel einer Container-Hierarchie dar. Zu den Top-Level Containern gehören:

  • das Hauptfenster (siehe ApplicationWindow)
  • modale und nicht-modale Dialoge (siehe Dialog)
  • Popup-Fenster (siehe PopupWindow)

Die gemeinsame Basisklasse für alle Top-Level Container ist com.cisag.pgm.gui.Window.

Die Top-Level Container bzw. Fenster stellen in Bezug auf die Container-Hierarchie jeweils die Wurzel dar, bilden aber untereinander wiederum eine Hierarchie. Diese „Fenster-Hierarchie“ ergibt sich nicht aus dem „enthalten-in“ wie bei den Containern, sondern aus einer „gehört-zu“ (owned-by) Beziehung. Wobei ein Fenster als zu einem anderen gehörend zählt, wenn es aus diesem erzeugt worden ist. In diesem Sinne stellt das Hauptfenster die (alleinige) Wurzel der Fenster-Hierarchie dar. Bei der Erzeugung von Dialogen und Popup-Fenstern ist jeweils das „erzeugende“ Fenster anzugeben. Die Fenster-Hierarchie spielt in folgenden Punkten eine Rolle:

  • x/y-Positionierung auf dem Bildschirm (relativ zu übergeordnetem Fenster).
  • z-Positionierung auf dem Bildschirm (das abhängige Fenster soll „vor“ dem übergeordneten Fenster liegen).
  • Schließen von Fenstern (beim Schließen eines übergeordneten Fensters sollen vorher automatisch alle abhängigen Fenster geschlossen werden).
  • Fokuswechsel (wenn ein abhängiges Fenster geschlossen wird, wechselt der Fokus automatisch in das übergeordnete Fenster).
  • Modale Dialoge (mehrere modale Dialoge können nur dann gleichzeitig sichtbar sein, wenn sie ineinander geschachtelt sind, d. h. wenn sie in der Fenster-Hierarchie eine gerade Linie ergeben).

Alle Top-Level Container bzw. Fenster sind nach ihrer Erzeugung (Instanziierung) zunächst noch „unsichtbar“, d. h. sie werden auf dem Bildschirm nicht dargestellt. Erst der explizite Aufruf von setVisible(true) „öffnet“ das Fenster. Mit setVisible(false) kann ein Fenster wieder „geschlossen“ und damit vom Bildschirm entfernt werden. Ein mehrmaliges Öffnen und Schließen, also die Wiederverwendung von Fenstern, mithilfe von setVisible(true/false) ist möglich[6]. Die entgültige „Zerstörung“ findet erst über dem Garbage-Collector statt.

Hinweis:
Solange ein Fenster noch in Benutzung ist, muss das Programm eine Referenz darauf halten, sonst besteht die Gefahr, dass das Fenster vorzeitig vom Garbage-Collector „zerstört“ wird.

3.2.1 ApplicationWindow

Die Klasse com.cisag.pgm.gui.ApplicationWindow repräsentiert das Hauptfenster von Semiramis. Bei einem Browser-basierten Client entspricht das dem Browser-Fenster.

Für jede Session existiert genau eine Instanz von com.cisag.pgm.gui.ApplicationWindow. Diese Instanz wird von der Semiramis-System-Engine bzw. dem UI-Framework zusammen mit der Session erzeugt.

Neben verschiedenen Informations- und Navigationsbereichen, stellt das Hauptfenster auch den Anwendungsbereich zur Verfügung. In diesem Bereich werden die UI-Anwendungen dargestellt bzw. ausgeführt.

  • ApplicationWindow

Die Kommunikation zwischen UI-Anwendung und Hauptfenster erfolgt grundsätzlich nur über die Methoden der Basisklasse (com.cisag.pgm.base.CisUiApplication) oder automatisch über das UI-Framework bzw. der System-Engine. Ein direkter Zugriff einer UI-Anwendung auf das Hauptfenster oder einer seiner Unterkomponenten ist nicht zulässig und kann die Funktionsweise aller Anwendungen beeinträchtigten.

Es gibt einen Sonderfall, in dem das Hauptfenster bzw. die Klasse ApplicationWindow innerhalb von UI-Anwendungen verwendet werden darf: Dialoge und Popup-Fenster benötigen als Unterfenster bei ihrer Erzeugung immer die Angabe des übergeordneten Fensters (Owner-Window). Wenn es sich dabei (definitiv) um das Hauptfenster handelt (siehe Hinweis unter 3.2.2 Dialog), kann man die benötigte Referenz normalerweise mit der Methode getWindow() bei CisUiApplication bekommen. Um zu vermeiden, dass alle betroffenen Objekte bzw. Methoden eine Referenz auf CisUiApplication kennen müssen, kann mit der statischen Methode currentWindow() bei ApplicationWindow ebenfalls die Referenz auf das Hauptfenster ermittelt werden.

3.2.2 Dialog

Auch wenn Dialoge, insbesondere modale, möglichst nicht verwendet werden sollten (siehe Dokument Styleguide), gibt es manchmal Fälle in den es „unumgänglich“ ist. Für diese Fälle steht die Klasse com.cisag.pgm.gui.Dialog bereit.

Hinweis:
Für das Anzeigen von Meldungen bzw. Bestätigungsdialogen sollte die Klasse com.cisag.pgm.gui.Confirmation Dialog verwendet werden.

Über einen Parameter im Konstruktor kann gewählt werden, ob es sich um einen modalen oder einen nicht-modalen Dialog handeln soll.

  • Modaler Dialog

Bei der Erzeugung von Dialogen sollte der Konstruktor Dialog(int, VisualElement, String) verwendet werden, da er folgende Vorteile besitzt:

  • Er stellt sicher, dass mit dem „öffnenden“ Element auch das richtige übergeordnete Fenster spezifiziert wird.
  • Das „öffnende“ Element dient dem Framework als Bezugpunkt für die Platzierung des Dialogs auf dem Bildschirm.
  • Der notwendige Dialogtitel wird bereits bei der Erzeugung des Dialogs und über das Repository festgelegt.

Hinweis:
Die Angabe des richtigen übergeordneten Fensters ist wichtig (siehe 3.2 Top-Level Container). Die Verwendung von CisUiApplication#getWindow() bzw. ApplicationWindow.currentWindow() ist daher nur dann zulässig, wenn sichergestellt werden kann, dass der Aufruf immer aus dem Hauptfenster erfolgt.

Wie bereits in 3.2 Top-Level Container beschrieben, wird ein Dialog erst mit dem Aufruf von setVisible(true) sichtbar. Vor dem Aufruf von setVisible(true), muss aber die Konstruktion und die Initialisierung des Dialogs und seiner Subelemente abgeschlossen sein. Der Aufruf von setVisible(true) ist sozusagen immer die letzte Anweisung beim Erzeugen eines Dialoges.

Bei modalen Dialogen ist zu berücksichtigen, dass anders als z. B. in AWT, der Aufruf von setVisible(true) nicht blockiert (wartet) bis der Dialog geschlossen wurde, sondern sofort zurückkommt.

Bei allen abgeleiteten Klassen von com.cisag.pgm.gui. Window ist der Zugriff auf die Container-Hierarchie nur über getContentPane() bzw. setContentPane() erlaubt (siehe 3.1.3 Window).

Die Größe (Breite bzw. Höhe) des Dialogs wird automatisch anhand der „preferredWidth“ bzw. „preferredHeight“ des Content-Panes berechnet. In einigen Fällen kann es notwendig sein, zumindest die gewünschte Breite des Dialogs explizit anzugeben. Das ist z. B. dann der Fall, wenn die verwendeten Elemente bzw. Layout-Manager keine sinnvollen Werte für „preferredWidth“ („preferredHeight“) liefern sollten (siehe 3.9.1 StandardLayout). Die Angabe einer Breite bzw. Höhe ist mithilfe der Methoden setWidth() bzw. setHeight() möglich, wobei damit nicht die Größe des Content-Panes, sondern des gesamten Dialoges (inkl. Rahmen und Titelleiste) spezifiziert wird. Bei beiden Methoden erfolgt die Werteangabe in Form von „Zeichenbreiten“, wodurch diese Angaben unabhängig von Schriftgröße bzw. Bildschirmauflösung sind.

In Kapitel „4.3 Dialoge verwenden“ wird der Umgang mit Dialogen anhand eines Codebeispiels verdeutlicht.

3.2.2.1 Dialog API

Die folgenden Tabellen zeigen die wichtigsten bzw. meistgenutzten Methoden von Dialog (eine vollständige Liste bzw. detaillierte Beschreibungen sind in der JavaDoc-Dokumentation von Dialog zu finden):

Tabelle 25: Konstruktoren
Methode Verwendung
Dialog(int,Window)

Dialog(int,Window,String)

Modalen oder nicht-modalen Dialog erzeugen (erster Parameter: Dialog.MODAL bzw. Dialog.NONMODAL).

Als zweiter Parameter (Window) ist das Fenster anzugeben, dass dem neuen Dialog übergeordnet ist. Optional kann als dritter Parameter eine Referenz auf ein Entwicklungsobjekt (DataDescription oder Stringtable) in Form eines (absoluten) Pfades spezifiziert werden. Aus diesem Entwicklungsobjekt wird dann der Text für die Titelleiste des Dialogs ermittelt. Wenn kein Pfad angegeben wurde, hat der Dialog keinen Titel. Mit den setTitle()-Methoden kann jedoch (vor setVisible(true)) noch ein Titel gesetzt werden.

Dialog(int,VisualElement)

Dialog(int,VisualElement, String)

Diese Gruppe von Konstruktoren verhält sich analog zu den oben aufgeführten Varianten mit Window als zweitem Parameter.

Das übergeordnete Fenster wird dabei automatisch (mit getWindow()) aus dem übergebenen VisualElement ermittelt. Dieses als „owner“ bezeichnete Element, ist das Element aus dem bzw. mit dem der Dialog geöffnet werden soll. Das Framework kann diese Information dazu nutzen, um den Dialog relativ zu diesem Element auf dem Bildschirm zu platzieren.

 

Tabelle 26: Allgemeiner Zustand
Methode Verwendung
isVisible()

setVisible(boolean)

Sichtbarkeit abfragen/ändern.

Ein Dialog wird erst durch ein explizites setVisible(true) auf dem Bildschirm sichtbar (geöffnet). Mit setVisible(false) kann der Dialog geschlossen werden.

isModal() Modalität abfragen.

Liefert true zurück, wenn der Dialog mit Dialog.MODAL erzeugt wurde. Die Modalität, also das modale bzw. nicht-modale Verhalten eines Dialogs kann nur im Konstruktor festgelegt werden.

isResizable()

setResizable(boolean)

Legt fest, ob der Benutzer den Dialog in seiner Größe ändern kann. Der Default hierfür ist true. Eine Änderung über setResizable() wirkt nur, wenn der Aufruf vor setVisible(true) erfolgt.

 

Tabelle 27: Metadatenunterstützung
Methode Verwendung
getTitle()

setTitle(String)

setTitleFrom(String)

setTitleFrom(String, String[])

Dialogüberschrift (Titel) abfragen, setzen oder ändern.

Der spezifizierte Text wird in der Titelleiste des Dialogs angezeigt. Es wird empfohlen, den Titel bereits im Konstruktor zu setzen. Wenn es nicht möglich ist, sollte eine der setTitleFrom()-Methoden benutzt werden.

 

Tabelle 28: Layout-Unterstützung
Methode Verwendung
getWidth()

setWidth(int)

getHeigth()

setHeight(int)

Breite und Höhe des Dialogs abfragen, setzen oder ändern.

Durch das explizite Setzen einer Breite bzw. Höhe lässt sich die automatische Berechnung (anhand der preferredWith/preferredHeight des Content-Panes) übersteuern. Die Angabe der Werte erfolgt in „Zeichenbreiten“ und gilt für die äußeren Abmessungen des Dialogs.

 

Tabelle 29: Implementierung
Methode Verwendung
closed() Dient als „Callback“ und kann von Subklassen überschrieben werden, die eine Benachrichtigung benötigen, wenn der Dialog geschlossen wurde.

 

3.2.3 PopupWindow

Popup-Fenster kann man als spezielle Dialogfenster verstehen, im Vergleich zu normalen Dialogen weisen sie jedoch folgende Unterschiede auf:

  • Sie können durch den Benutzer nicht verschoben und auch nicht in ihrer Größe geändert werden.
  • Sie sind immer einem anderen Element zugeordnet und werden in dessen unmittelbarer Nähe geöffnet.
  • Sie besitzen keine Titelleiste.
  • Keine Unterscheidung zwischen modal/nicht-modal, stattdessen ist immer nur ein Popup-Fenster möglich (automatisches Schließen, wenn ein Mausklick außerhalb des Fensters erfolgt).

Verwendet werden Popup-Fenster überwiegend von dem UI-Framework selbst, zum Beispiel als Basis für Comboboxen, Kontextmenüs, Dropdown-Menüs und die Direkthilfe. Aber auch auf Anwendungsebene kommt eine Verwendung immer dann in Betracht, wenn die optische Nähe zu dem „öffnenden“ Element besonders wichtig ist. Ein gutes Beispiel hierfür sind die Rauten-Buttons.

  • PopupWindow

Wie bereits in 3.2 Top-Level Container beschrieben, wird ein Popup-Fenster (Window) erst mit dem Aufruf von setVisible(true) sichtbar. Vor dem Aufruf von setVisible(true), muss aber die Konstruktion und die Initialisierung des Popup-Fensters und seiner Subelemente abgeschlossen sein, der Aufruf von setVisible(true) ist immer die letzte Anweisung beim Erzeugen eines Popup-Fensters.

Wie bei allen abgeleiteten Klassen von com.cisag.pgm. gui.Window, ist der Zugriff auf die Container-Hierarchie nur über getContentPane() bzw. setContentPane() erlaubt (siehe 3.1.3 Window).

Die Größe (Breite bzw. Höhe) des Popup-Fensters wird automatisch anhand der „preferredWidth“ bzw. „preferredHeight“ des Content-Panes berechnet. Es stehen zwar, wie bei Dialogen, die Methoden setWidth() bzw. setHeight() zur Verfügung, die Implementierungen dieser Methoden rufen jedoch einfach setPreferredWidth() bzw. setPreferredHeight() auf. Da diese Implementierung nicht unabhängig von der Schriftgröße bzw. Bildschirmauflösung ist, wurde sie auf „deprecated“ gesetzt, und sollte nicht verwendet werden. Wenn die Angabe einer festen Größe unbedingt erforderlich ist, sollte setPreferredWidth() bzw. setPreferredHeight() direkt bei dem Content-Pane aufgerufen werden.

3.2.3.1 PopupWindow API

Die folgenden Tabellen zeigen die wichtigsten bzw. meistgenutzten Methoden von PopupWindow (eine vollständige Liste bzw. detaillierte Beschreibungen sind in der JavaDoc-Dokumentation von PopupWindow zu finden):

Tabelle 30: Konstruktoren
Konstruktor Verwendung
PopupWindow(
VisualElement)
Popup-Fenster erzeugen.

Als Parameter (VisualElement) ist das Element anzugeben, aus dem bzw. mit dem das Popup-Fenster geöffnet werden soll. Dieses Element wird einerseits dazu benutzt, das übergeordnete Fenster zu ermitteln, und anderseits um das Popup-Fenster zu positionieren.

 

Tabelle 31: Visuelles Erscheinungsbild
Methode Verwendung
setShadowVisible(int) Legt fest, ob das Popup-Window mit einem Schatten hinterlegt werden soll, bzw. wie breit dieser Schatten in Pixeln sein soll.

Der Default wird durch das Framework festgelegt und sollte im Allgemeinen nicht geändert werden.

 

Tabelle 32: Allgemeiner Zustand
Methode Verwendung
isVisible()

setVisible(boolean)

Sichtbarkeit abfragen und ändern.

Ein Popup-Fenster wird erst durch ein explizites setVisible(true) auf dem Bildschirm sichtbar (geöffnet). Mit setVisible(false) kann das Popup-Fenster geschlossen werden.

setAutoHide(boolean) Legt fest, ob das Popup-Fenster automatisch geschlossen werden soll, wenn der Benutzer ein Element außerhalb des Popup-Fensters anklickt.

Der Default hierfür ist true. Eine Änderung über setAutoHide() wirkt nur, wenn der Aufruf vor setVisible(true) erfolgt.

 

Tabelle 33: Positionierung
Methode Verwendung
dockTo(VisualElement) Positioniert das Popup-Fenster in der Nähe des angegebenen Elements.

Normalerweise ist ein Aufruf dieser Methode nicht notwendig, da das Element bereits im Konstruktor übergeben wurde.

 

3.3 Standard-Container

Das Framework bietet eine Reihe von Standard-Containern an. Hierbei handelt es sich um konkrete Subklassen von com.cisag.pgm.gui.VisualElementContainer. Jede dieser Subklassen hat spezielle Eigenschaften bezüglich Aussehen, Strukturierung und/oder Interaktivität.

3.3.1 View

Die Klasse View erfüllt den selben Zweck wie java.awt.Panel in AWT bzw. javax.swing.JPanel in Swing. Ein View hat selbst keine visuellen Eigenschaften (Farbe, Rahmen, Titel, o. ä.). Er dient praktisch nur dazu andere Elemente zu gruppieren und (über einen Layout-Manager) zu layouten. Im Vergleich zu seiner Elternklasse (VisualElementContainer) stellt View keine zusätzliche Funktionalität zur Verfügung, mit Ausnahme der öffentlichen Konstruktoren.

In den APIs von Semiramis wird häufig com.cisag.pgm. gui.View statt com.cisag.pgm.gui.VisualElement Container verwendet. Aus diesem Grund dient com.cisag.pgm.gui.View auch als Basisklasse für die meisten anderen Standard-Container.

3.3.1.1 View API

Die folgenden Tabellen zeigen die wichtigsten bzw. meistgenutzten Methoden von View (eine vollständige Liste bzw. detaillierte Beschreibungen sind in der JavaDoc-Dokumentation von View zu finden):

Tabelle 34: Konstruktoren
Konstruktor Verwendung
View()

View(LayoutManager)

Erzeugt einen einfachen Container.

Optional kann beim Aufruf bereits ein Layout-Manager übergeben werden

View(String)

View(String, LayoutManager)

Diese Gruppe von Konstruktoren erlaubt zusätzlich die Spezifikation eines Pfades.

 

3.3.2 GroupBox

Anders als z. B. ein View, besitzt eine GroupBox auch eigene visuelle Eigenschaften. Die GroupBox nutzt Titel, Randabstände (Margins) und Hintergrundfarbe um die, in ihr enthaltenen Elemente nicht nur logisch, sondern auch optisch zusammenzufassen.

  • GroupBoxen (untereinanderliegend)

Das Verhalten bzw. das Aussehen von GroupBoxen läßt sich über die Eigenschaft „style“ beeinflussen:

Tabelle 35: „Style“-Eigenschaft von GroupBox und Shelf
style Verhalten
STYLE_GROUPBOX Standard-GroupBox mit Titel und nicht unterdrückbarem Anzeigebereich.
STYLE_SEPARATOR Ähnlich zu STYLE_GROUPBOX, es wird jedoch statt einer Titelleiste nur eine dünne Trennlinie verwendet
STYLE_SHELF Der Anzeigebereich kann über eine zusätzliche Schaltfläche in der Titelleiste durch den Benutzer sichtbar oder unsichtbar gemacht werden (d. h. „aufgeklappt“ bzw. „zugeklappt“ werden).

Weiterhin erlaubt die Titelleiste die Aufnahme weiterer UI-Elemente.

STYLE_SUBSHELF Platzsparende Variante eines Shelfs (kein Titel oder Titelleiste.

Keine optische Abgrenzung durch Rahmen oder Hintergrundfarbe.

 

Typischerweise wird die Eigenschaft „style“ jedoch automatisch vorbelegt, z. B. durch die Wahl der Klasse und/oder das Vorhandensein bestimmter Eigenschaften (z. B Titel). Das direkte Setzen von „style“ ist daher meistens nicht notwendig und sollte vermieden werden.

Die Klasse com.cisag.pgm.gui.GroupBox ist zugleich die Basisklasse für com.cisag.pgm.gui.Shelf (siehe 3.3.3 Shelf). Die Implementierung von „Shelf“ stellt (etwas vereinfacht dargestellt) nur eine spezielle Konfiguration der GroupBox dar.

Im Konstruktor wird einer GroupBox (und auch Shelfs) ein StandardLayout als Layout-Manager zugeordnet. Dieser Layout-Manager ist jedoch nicht zwingend und kann bei Bedarf über die Methode setLayout()durch einen anderen ersetzt werden.

3.3.2.1 GroupBox API

Die folgenden Tabellen zeigen die wichtigsten bzw. meistgenutzten Methoden von GroupBox (eine vollständige Liste bzw. detaillierte Beschreibungen sind in der JavaDoc-Dokumentation von GroupBox zu finden):

Tabelle 36: Konstruktoren
Konstruktor Verwendung
GroupBox(String)

GroupBox(String, String)

Erzeugt eine GroupBox (STYLE_GROUPBOX).

Als Parameter können entweder eine GUID und bei Bedarf zusätzlich ein Pfad übergeben werden.

Die GUID dient zur Identifizierung der GroupBox (siehe 3.1.4.1 Generelle Eigenschaften). Über den Pfad (DataDeschription oder Stringtable) wird der Titel der GroupBox aus dem Repository geladen.

 

Tabelle 37: Visuelles Erscheinungsbild
Methode Verwendung
STYLE_GROUPBOX

STYLE_SEPARATOR

STYLE_SHELF

STYLE_SUBSHELF

getStyle()

setStyle(int)

Aussehen und Verhalten (Stil) abfragen, setzen oder ändern.

Wird in der Regel automatisch festgelegt.

isCollapsible() Liefert true, wenn dem Benutzer eine Schaltfläche zum Auf-/Zuklappen des Anzeigebereichs angeboten wird.

Diese Eigenschaft ist nur für Shelfs (style==STYLE_SHELF bzw. style==STYLE_SUBSHELF) relevant. Ein „Setter“ für diese Eigenschaft ist nur in der Subklasse „Shelf“ verfügbar.

setMargins(boolean) Legt fest, ob bei der GroupBox die Standardrandabstände (Margins) benutzt werden sollen oder nicht.

 

Tabelle 38: Allgemeiner Zustand
Methode Verwendung
isCollapsed()

setCollapsed(boolean)

Sichtbarkeit des Anzeigebereichs abfragen und ändern.

Bei collapsed==true, wird die Anzeige des Anzeigebereichs unterdrückt (zugeklappt). Diese Eigenschaft ist nur für Shelfs (style==STYLE_SHELF bzw. style==STYLE_SUBSHELF) relevant.

 

Tabelle 39: Metadatenunterstützung
Methode Verwendung
getTitle()

setTitle(String)

setTitleFrom(String)

setTitleFrom(String, String[])

Überschrift (Titel) abfragen, setzen oder ändern.

Der spezifizierte Text wird in der Titelleiste der GroupBox angezeigt. Zum Setzen des Titels sollte entweder bereits im Konstruktor ein Pfad übergeben oder eine der setTitleFrom()-Methoden benutzt werden.

 

3.3.3 Shelf

Ein Shelf ist eine spezielle GroupBox (siehe 3.3.2 GroupBox) mit „klappbarem“ Anzeigebereich. Durch das Zuklappen, kann die GroupBox bzw. das Shelf auf ihre Titelleiste reduziert werden.

  • typisches Shelf (aufgeklappt)

Das Shelf ist in zwei Ausführungen verfügbar:

  • Das typische Shelf besitzt, wie eine GroupBox, eine Titelleiste und nutzt, ebenfalls wie die GroupBox, spezielle Hintergrundfarben zur optischen Abgrenzung von anderen Elementen.
  • Das „Subshelf“ verwendet hingegen keine besondere Umrandung oder Hintergrundfarbe, es besitzt lediglich eine Schaltfläche zum Auf-/Zuklappen. Es eignet sich daher besonders für die Fälle, in denen innerhalb einer GroupBox oder eines Shelf noch eine weitere (klappbare) Gruppe benötigt wird.
  • GroupBox mit innenliegendem Subshelf (aufgeklappt)

Die Auswahl zwischen Shelf bzw. Subshelf erfolgt automatisch über den Titel, d. h. wenn bei einem Objekt der Klasse „Shelf“ ein Titel gesetzt wird, wird es als „normales“ Shelf mit Titelleiste dargestellt. Wenn dem Shelf jedoch kein Titel zugewiesen wird, dann wird es als Subshelf dargestellt. Dieses Verhalten ist auch über die Eigenschaft „style“ (siehe 3.3.2 GroupBox) explizit steuerbar.

Das Shelf unterstützt, anders als die GroupBox, auch die Erweiterung der Titelleiste um zusätzliche Elemente.

  • Shelf mit zusätzlichen Elementen in der Titelleiste

Mit setHeader() kann nur genau ein Element hinzugefügt werden, das kann jedoch auch ein Container mit Subelementen sein. Bei dem hinzugefügten Element sollte die Eigenschaft „alignmentX“ explizit gesetzt werden. Also z. B. auf VisualElement.RIGHT_ALIGNMENT, wenn das Element rechtsbündig in der Titelleiste erscheinen soll.

3.3.3.1 Shelf API

Die folgenden Tabellen zeigen die wichtigsten bzw. meistgenutzten Methoden von Shelf (eine vollständige Liste bzw. detaillierte Beschreibungen sind in der JavaDoc-Dokumentation von Shelf zu finden):

Tabelle 40: Konstruktoren
Konstruktor Verwendung
Shelf(String)

Shelf(String, String)

Erzeugt ein Shelf (STYLE_SHELF) oder Subshelf (STYLE_SUBSHELF).

Die Entscheidung, ob Shelf oder Subshelf, wird automatisch anhand des Vorhandenseins eines Titels getroffen, wobei der Titel auch später gesetzt werden kann.

Wie bei der Elternklasse (GroupBox) könnnen als Parameter entweder eine GUID oder eine GUID und ein Pfad übergeben werden. Die GUID dient zur Identifizierung des Shelfs (siehe 3.1.4.1 Generelle Eigenschaften). Über den Pfad (DataDeschription oder Stringtable) wird der Titel des Shelfs aus dem Repository geladen.

 

Tabelle 41: Visuelles Erscheinungsbild
Methode Verwendung
setCollapsible(boolean) Legt fest, ob die Schaltfläche zum Auf-/Zuklappen sichtbar sein soll oder nicht.

Der Standardwert ist true

getHeader()

setHeader(VisualElement)

Hinzufügen eines zusätzlichen Elements im Bereich der Titelleiste.

Es kann nur ein Element hinzugefügt werden, bei einem erneuten Aufruf von setHeader() wird das zuvor gesetzte Element ersetzt. Es ist möglich, einen Container mit Subelementen zu setzen.

 

Tabelle 42: Ereignisbehandlung
Methode Verwendung
setMaximizeAction(Action) Neue „Maximize-Action“ registrieren.

Diese Action kann verwendet werden, wenn die Sichtbarkeit von mehreren Shelfs miteinander synchronisiert werden soll.

Ein Beispiel ist der Navigationsbereich von Semiramis. Die Shelfs „Anwendungsbezogene Favoriten“, „Favoriten“ und „Anwendungen“ werden dort mit dieser Action gesteuert. Wenn eines der genannten Shelfs diese Action auslöst, wird dieses geöffnet und die anderen gleichzeitig geschlossen. Somit steht einem Shelf der „maximale“ Platz zur Verfügung. Der Auslöser für die Action ist typischerweise ein Klick auf den Titel des Shelfs.

 

3.3.4 ScrollPane

Die Klasse com.cisag.pgm.gui.ScrollPane erweitert die Klasse View (siehe 3.3.1 View) um die Fähigkeit, den Inhalt eines Containers ausschnittsweise betrachten zu können. Diese Fähigkeit ist immer dann von Bedeutung, wenn die verfügbare Fläche nicht ausreicht, um den Inhalt eines Containers vollständig anzuzeigen.

Das ScrollPane zeigt von dem gesamten Container-Inhalt, immer nur soviel an, wie die zur Verfügung stehende Fläche zulässt. Gleichzeitig erlaubt es dem Benutzer den betrachteten Ausschnitt zu verschieben. Auf diese Weise wird die Zugänglichkeit des gesamten Inhalts ermöglicht.

Die Verschiebung des Inhalts erfolgt durch Scrollbalken. Wobei für die horizontale und die vertikale Verschiebung jeweils ein eigner Scrollbalken vorgesehen ist.

Bei der Verwendung von ScrollPanes sind aus ergonomischer Sicht folgende Punkte zu beachten:

  • Die Schachtelung von scrollbaren Bereichen, dazu zählen nicht nur ScrollPanes[7], ist unbedingt zu vermeiden.
  • Auf horizontales Scrollen sollte verzichtet werden, da dies ergonomisch ähnlich problematisch ist, wie die Schachtelung von scrollbaren Bereichen.
  • Bei Listen und Tabellen sollte auf Scrollbalken verzichtet werden, wenn diese „Blättern“ können.

Bei dem ScrollPane lassen sich daher horizontale und vertikale Scrollbalken getrennt freischalten, wobei jeweils drei Modi (policies) zur Verfügung stehen:

  • Scrollbalken nie verwenden (*_SCROLLBAR_NEVER), d. h. die Inhalte werden ggf. abschnitten.
  • Scrollbalken immer verwenden/anzeigen (*_SCROLLBAR_ALWAYS), d. h. die Scrollbalken werden auch angezeigt, wenn sie eigentlich nicht benötigt werden.
  • Scrollbalken nur bei Bedarf verwenden/anzeigen (*_SCROLLBAR_AS_NEEDED), d. h. die Scrollbalken werden nur dann angezeigt, wenn sie tatsächlich benötigt werden.

Für die horizontalen Scrollbalken gilt praktisch immer HORIZONTAL_SCROLLBAR_NEVER. Die Gefahr des Abschneidens ist dabei i.d.R. nicht gegeben, da die verwendeten Elemente und Layout-Manager speziell hierfür ausgelegt sind (automatische Anpassung des Inhalts an die Breite).

Für das vertikale Scrolling gilt hingegen: Es sollte, bezogen auf die Container-Hierarchie eines Elements, immer genau ein Element/Container scrollbar sein und die Einstellung VERTICAL_SCROLLBAR_AS_NEEDED besitzen. Es ist erlaubt, weitere scrollbare Elements/Container zu verwenden, allerdings müssen diese dann die Einstellung VERTICAL_SCROLLBAR_NEVER besitzen. Einige Elemente (z. B. TabbedPane) stellen das teilweise selbst sicher, indem sie beim Einfügen in einen Container prüfen, ob es sich bei diesem um ein scrollbaren Container handelt und diesen ggf. auf VERTICAL_SCROLLBAR_NEVER setzen.

3.3.4.1 ScrollPane API

Die folgenden Tabellen zeigen die wichtigsten bzw. meistgenutzten Methoden von ScrollPane (eine vollständige Liste bzw. detaillierte Beschreibungen sind in der JavaDoc-Dokumentation von ScrollPane zu finden):

Tabelle 43: Konstruktoren
Konstruktor Verwendung
ScrollPane()

ScrollPane(Layout)

ScrollPane(String)

ScrollPane(String, LayoutManager)

Erzeugt ein ScrollPane mit HORIZONTAL_SCROLLBAR_NEVER und VERTICAL_SCROLLBAR_AS_NEEDED.

Optional kann ein Layout-Manager und/oder Pfad spezifiziert werden.

ScrollPane(int, int)

ScrollPane(LayoutManager, int, int)

ScrollPane(String,
int, int)

ScrollPane(String, LayoutManager,int,int)

Erzeugt ein ScrollPane gemäß den spezifizierten Regeln (policies) für den horizontalen bzw. vertikalen Scrollbalken.

Optional kann ein Layout-Manager bzw. Pfad spezifiziert werden.

 

Tabelle 44: Allgemeiner Zustand
Methode Verwendung
HORIZONTAL_SCROLLBAR_AS_NEEDED

HORIZONTAL_SCROLLBAR_NEVER

HORIZONTAL_SCROLLBAR_ALWAYS

getHorizontalScrollBarPolicy()

setHorizontalScrollBarPolicy(int)

Regeln für die Verwendung des horizontalen Scrollbalken festlegen bzw. abfragen.

Sollte praktisch immer auf HORIZONTAL_SCROLLBAR_NEVER

gesetzt werden.

VERTICAL_SCROLLBAR_AS_NEEDED

VERTICAL_SCROLLBAR_NEVER

VERTICAL_SCROLLBAR_ALWAYS

getVerticalScrollBarPolicy()

setVerticalScrollBarPolicy(int)

Regeln für die Verwendung des vertikalen Scrollbalken festlegen bzw. abfragen.

Nur (genau) ein ScrollPane bzw. anderes scrollbares Element sollte VERTICAL_SCROLLBAR_AS_NEEDED

verwenden. Alle anderen sollten auf VERTICAL_SCROLLBAR_NEVER gesetzt werden.

 

3.3.5 SplitPane

Die Klasse com.cisag.pgm.gui.SplitPane ist ein von View (siehe 3.3.1 View) abgeleiteter Container, dessen Anzeigefläche in zwei Bereiche unterteilt ist. Diese Bereiche können wahlweise nebeneinander oder übereinander liegen. Jedem dieser Bereiche kann genau ein VisualElement zu geordnet werden, wobei als VisualElement natürlich auch Container möglich sind.

Zwischen den beiden Bereichen befindet sich eine Trennlinie („Divider“). Diese Trennlinie dient gleichzeitig als „Griff“ für den Benutzer. Durch Verschieben dieser Trennlinie kann ein Bereich jeweils zu Lasten oder Gunsten des anderen Bereichs vergrößert oder verkleinert werden.

Das Hinzufügen von Elementen muss bei dem SplitPane über spezielle Methoden (z. B. setLeftComponent(Visual Element)) erfolgen, die Verwendung der add(…)-Methoden ist nicht zulässig bzw. führt zu einem undefiniertem Verhalten.

Anders als bei den üblichen Containern, wird die Größe der enthaltenen Elemente nicht durch einen Layout-Manager bestimmt, sondern kann direkt durch den Benutzer verändert werden. Das Setzen eines Layout-Managers ist nicht notwendig und wird auch nicht unterstützt.

3.3.5.1 SplitPane API

Die folgenden Tabellen zeigen die wichtigsten bzw. meistgenutzten Methoden von SplitPane (eine vollständige Liste bzw. detaillierte Beschreibungen sind in der JavaDoc-Dokumentation von SplitPane zu finden):

Tabelle 45: Konstruktoren
Konstruktor Verwendung
SplitPane(String) Erzeugt ein SplitPane mit horizontaler Teilung (HORIZONTAL_SPLIT).

Der Parameter (GUID) dient zur Identifizierung des SplitPanes (siehe 3.1.4.1 Generelle Eigenschaften).

SplitPane(String, int)

SplitPane(String, int, double)

Erlaubt die Spezifikation der Teilungsrichtung (HORIZONTAL_SPLIT, VERTICAL_SPLIT) bereits bei der Erzeugung.

Mit dem dritten Parameter kann zusätzlich das Breitenverhältnis der beiden Bereiche festgelegt werden (siehe setInitialDivi-derLocation()).

 

Tabelle 46: Visuelles Erscheinungsbild
Methode Verwendung
getDividerSize()

setDividerSize(int)

Legt die Breite der Trennlinie zwischen den beiden Bereichen fest.

Diese Breite wird vom UI-Framework vorbelegt und sollte nicht geändert werden.

 

Tabelle 47: Allgemeiner Zustand
Methode Verwendung
setInitialDividerLocation(int)

setInitialDividerLocation(double)

Legt programmseitig fest, an welcher Position sich die Trennlinie (Divider) befinden soll.

Durch die Position der Trennlinie wird auch die Breite der beiden Bereiche bestimmt. Die Angabe kann entweder als absoluter Wert (Pixel) oder als relativer Wert (0.0 bis 1.0) spezifiziert werden. Der Wert „0.5“ würde z. B. „in der Mitte“ bedeuten.

Ein Abfragen der aktuellen Position ist mit dieser Version des SplitPanes nicht möglich.

 

Tabelle 48: Container-Hierarchie und Layout-Management
Methode Verwendung
HORIZONTAL_SPLIT

VERTICAL_SPLIT

getOrientation()

setOrientation(int)

Legt fest, ob die Anzeigebereiche nebeneinander (HORIZONTAL_SPLIT) oder übereinander (VERTICAL_SPLIT) liegen sollen.
getLeftComponent()

setLeftComponent(
VisualElement)

getRightComponent()

setRightComponent(
VisualElement)

Fügt ein VisualElement in den linken oder rechten Bereich ein, bzw. liefert das aktuelle Element in diesem Bereich zurück.

Diese Methoden sollten nur verwendet werden, wenn bei dem SplitPane die horzizontale Teilung gewählt wurde (orientation == HORIZONTAL_SPLIT).

getTopComponent()

setTopComponent(
VisualElement)

getBottomComponent()

setBottomComponent(
VisualElement)

Fügt ein VisualElement in den oberen oder unteren Bereich ein, bzw. liefert das aktuelle Element in diesem Bereich zurück.

Diese Methoden sollten nur verwendet werden, wenn bei dem SplitPane die vertikale Teilung gewählt wurde (orientation == VERTICAL_SPLIT).

clear() Löscht alle Elemente (Bereiche).

Diese Methode sollte statt remove() bzw. removeAll() verwendet werden.

 

3.3.6 TabbedPane

Die Klasse com.cisag.pgm.gui.TabbedPane ist ein von View (siehe 3.3.1 View) abgeleiteter Container, der jeweils nur eines seiner Subelemente anzeigt. Dem Benutzer präsentiert sich das TabbedPane wie ein Karteikasten mit Karteireitern (Tabs), wobei jedem Subelement ein eigener Karteireiter (Tab) zugeordnet ist. Durch die Auswahl eines Karteireiters wird das zugeordnete Element[8] sichtbar.

  • TabbedPane

Die Karteireiter werden typischerweise im oberen Bereich des TabbedPanes angezeigt (oberhalb des ausgewählten Subelements). Mit der Methode setTabPlacement() kann die Position der Karteireiter auch verändert werden.

Das Hinzufügen von Elementen bzw. Karteireitern muss bei dem TabbedPane über spezielle Methoden (addTab(…), insertTab(…)) erfolgen. Die Verwendung der add(…)-Methoden ist nicht zulässig bzw. führt zu einem undefiniertem Verhalten. Bei addTab() bzw. insertTab() ist neben dem Element auch eine Action zu übergeben. Diese Action (i.d.R. mithilfe von Metadaten aus dem Repository erzeugt) definiert einerseits den Text, ToolTip und/oder Icons für den Karteireiter und dient anderseits auch als Identifizierung und Steuerung des damit erzeugten Karteireiters. Über diese Action lässt sich z. B. der Karteireiter selektieren, „disablen“ oder wieder aus dem TabbedPane entfernen. Außerdem kann man sich bei dieser Action auch als ActionListener registrieren und auf diese Weise benachrichtigt werden, wenn der zugehörige Karteireiter geöffnet wird.

Das TabbedPane verwendet intern einen eigenen Layout-Manager, daher ist das Setzen eines anderen Layout-Managers nicht möglich bzw. unzulässig.

3.3.6.1 TabbedPane API

Die folgenden Tabellen zeigen die wichtigsten bzw. meistgenutzten Methoden von TabbedPane (eine vollständige Liste bzw. detaillierte Beschreibungen sind in der JavaDoc-Dokumentation von TabbedPane zu finden):

Tabelle 49: Konstruktoren
Konstruktor Verwendung
TabbedPane(String) Erzeugt ein leeres TabbedPane mit obenstehenden Karteireitern (TOP).

Der Parameter (GUID) dient zur Identifizierung des TabbedPane (siehe 3.1.4.1 Generelle Eigenschaften).

 

Tabelle 50: Visuelles Erscheinungsbild
Methode Verwendung
TOP

BOTTOM

LEFT

RIGHT

getTabPlacement()

setTabPlacement(int)

Legt die Position der Karteireiter (Tabs) fest.

Die Karteireiter können wahlweise am obereren (TOP), unterern (BOTTOM), linken (LEFT) oder rechten (RIGHT) Rand des TabbedPanes platziert werden. Die Voreinstellung ist TOP.

DEFAULT_TABS

SMALL_TABS

EQUALS_TABS

EXPANDED_TABS

getTabStyle()

setTabStyle(int)

Legt die Größen für die Karteireiter (Tabs) fest.

• Mit SMALL_TABS wird die Schriftgröße reduziert,

• mit EQUALS_TABS wird festgelegt, dass alle Karteireiter die gleiche Breite haben sollen und

• EXPANDED_TABS legt fest, dass die Karteireiter über die gesamte Breite des TabbedPanes verteilt werden (sonst erfolgt die Anordnung linksbündig).

Diese drei Werte können miteinander kombiniert (OR-verknüpft) werden. Wird keiner der Werte angegeben, so entspricht dies dem Wert DEFAULT_TABS.

Die Verwendung von SMALL_TABS, EQUALS_TABS und/oder EXPANDED_TABS ist nur zulässig, wenn die Position der Karteireiter auf TOP oder BOTTOM eingestellt ist.

NO_SCROLL_TAB_LAYOUT

SCROLL_TAB_LAYOUT

AUTO_SCROLL_TAB_LAYOUT

getTabLayoutPolicy()

setTabLayoutPolicy(int)

Legt fest, wie sich der Karteireiterbereich bei Platzmangel verhalten soll.

• Bei NO_SCROLL_TAB_LAYOUT werden immer alle Karteireiter dargestellt, ggf. werden die Beschriftungen der Karteireiter verkürzt (Anzeige von „…“).

• Bei SCROLL_TAB_LAYOUT werden die Texte vollständig angezeigt, aber ggf. die Anzahl der angezeigten Karteireiter reduziert (über zusätzliche Scrollelemente, und Dropdown-Menü sind alle Karteireiter zugänglich).

• Bei AUTO_SCROLL_TAB_LAYOUT wechselt das TabbedPane automatisch von NO_SCROLL_TAB_LAYOUT auf SCROLL_TAB_ LAYOUT, wenn nicht genügend Platz verhanden ist.

Die Voreinstellung ist NO_SCROLL_TAB_ LAYOUT. Die Änderung dieser Einstellung wird nur bei obenliegenden Karteireitern (TOP) unterstützt.

 

Tabelle 51: Verwaltung von Karteireitern
Methode Verwendung
addTab(Action, VisualElement) Erstellt einen neuen Karteireiter (Tab) für das übergebene Element und fügt diesen hinter dem letzten bereits vorhandenen Karteireiter ein.

Aus der Action wird der Text, ToolTip und/oder Icons für die Beschriftung sowie der „enabled“-Zustand übernommen.

insertTab(Action, VisualElement, int) Verhält sich wie addTab, jedoch kann mit dieser Methode der neue Karteireiter nicht nur am Ende, sondern an einer beliebigen Position eingefügt werden.
removeTab(Action) Entfernt den Karteireiter, der zu der übergebenen Action gehört, d. h. der mithilfe dieser Action erstellt/hinzugefügt wurde.

Die Karteireiter müssen mit dieser Methode entfernt werden, die Benutzung von remove() bzw. removeAll() ist nicht zulässig.

getTabCount() Liefert die aktuelle Anzahl von Karteireitern zurück.
getActions() Liefert eine Liste (java.util.ArrayList) mit allen Actions zurück für die aktuell Karteireiter vorhanden sind.

Die Liste darf nicht modifiziert werden.

getSelectedAction()

setSelectedAction(Action)

Liefert die Action zurück, die dem aktuell selektiertem Karteireiter entspricht, bzw. selektiert (wählt) programmseitig den Karteireiter, der der übergebenen Action entspricht.
getSelectedActionId()

setSelectedActionId(int)

Wie getSelectedAction() bzw. setSelectedAction(), jedoch wird hier nicht die Action selbst, sondern nur ihre ID verwendet.
getTabVisiblity(Action)

setTabVisibility(Action, boolean)

Erlaubt einen Karteireiter auszublenden, ohne ihn entfernen zu müssen.
setTabVisibility(int, boolean) Wie setTabVisibility(Action, boolean), jedoch wird hier nicht die Action selbst, sondern nur ihre ID verwendet.

 

3.3.7 LayeredPane

Die Klasse com.cisag.pgm.gui.LayeredPane ist ein von View (siehe 3.3.1 View) abgeleiteter Container, der (wie TabbedPane) jeweils nur eines seiner Subelemente anzeigt. Im Gegensatz zu dem TabbedPane, besitzt das Layered-Pane keine Bedienelemente zum Umschalten des angezeigten Subelements. Die Umschaltung ist nur programmseitig möglich. Außerdem muss es sich bei den (hier als „Layer“ bezeichneten) Subelementen um Instanzen von View handeln (bei TabbedPane werden Instanzen von Visual-Element verwaltet).

Hinweis:
Die Funktionsweise von LayeredPane ist nicht vergleichbar mit dem JLayeredPane aus Swing (dort sind mehrere Elemente gleichzeitig sichtbar und können sich beliebig überlappen).

Das Hinzufügen von „Layern“ bzw. Subelementen (Views). muss bei dem LayeredPane über spezielle Methoden (addLayer(…), insertLayer(…)) erfolgen, die Verwendung der add(…)-Methoden ist nicht zulässig bzw. führt zu einem undefiniertem Verhalten.

3.3.7.1 LayeredPane API

Die folgenden Tabellen zeigen die wichtigsten bzw. meistgenutzten Methoden von LayeredPane (eine vollständige Liste bzw. detaillierte Beschreibungen sind in der JavaDoc-Dokumentation von LayeredPane zu finden):

Tabelle 52: Konstruktoren
Konstruktor Verwendung
LayeredPane() Erzeugt ein leeres LayeredPane.

 

Tabelle 53: Verwaltung von „Layern“
Methode Verwendung
addLayer(View) Fügt das spezifierte Element (View) als neue „Layer“ hinter der letzten bereits vorhandenen Layer ein.
insertLayer(View, int) Verhält sich wie addLayer, jedoch kann mit dieser Methode die neue „Layer“ nicht nur am Ende, sondern an einer beliebigen Position eingefügt werden.
removeLayer(int) Entfernt die Layer, die sich an der übergebenen Position befindet.

Die Subelemente (Layers) müssen mit dieser Methode entfernt werden, die Benutzung von remove() bzw. removeAll() ist nicht zulässig.

getLayerCount() Liefert die aktuelle Anzahl von Layern zurück.
getLayer(int) Liefert den View (Layer) zurück, der sich an der übergebenen Position (Index) befindet.
getSelectedLayer() Liefert den aktuell angezeigten (selektierten) View (Layer) zurück.
getSelectedIndex()

setSelectedIndex(int)

Liefert den Index des aktuell angezeigten (selektierten) Views zurück, bzw. zeigt den View mit dem spezifizierten Index an.

 

3.4 Standardelemente

3.4.1 Label

Die Klasse com.cisag.pgm.gui.Label dient der Anzeige von statischen (nicht editierbaren) Texten und Grafiken (Icons). Text und Icon können sowohl einzeln verwendet als auch miteinander kombiniert werden.

Ein Label kann als Beschriftung für ein anderes VisualElement dienen. Mithilfe der Methode setLabelFor() kann zwischen dem Label und dem betroffenen Element eine explizite Verknüpfung hergestellt werden. Diese Verknüpfung ist notwendig, damit das Label bestimmte Ereignisse (Mausklicks, Access-Keys, …) an das zu ihm gehörende Element weiterleiten kann. Auch bestimmte Layout-Manager (z. B. StandardLayout) nutzen diese explizite Verknüpfung, um Label und Element entsprechend zu platzieren.

Hinweis:
Felder, d. h. Subklassen von com.cisag.pgm.gui.Field (vgl. Kapitel 3.5 Felder), besitzen ein integriertes Label und benötigen daher kein zusätzliches Label.

Das Label kann auch als Hyperlink benutzt werden. Neben der, von VisualElement geerbten, Möglichkeit eine „Link-Action“ zu setzen, kann mit der Methode setUrl() auch eine URL als Ziel für den Hyperlink definiert werden.

Obwohl das Label prinzipiell für jede Art von nicht editierbaren „Daten“ verwendet kann, stehen hierfür in Semiramis spezielle Subklassen von com.cisag.pgm.gui.Field zur Verfügung.

3.4.1.1 Label API

Die folgenden Tabellen zeigen die wichtigsten bzw. meistgenutzten Methoden von Label (eine vollständige Liste bzw. detaillierte Beschreibungen sind in der JavaDoc-Dokumentation von Label zu finden).

Hinweis:
Der Zugriff auf die meisten Methoden ist erst möglich, nachdem das Label einem Container hinzugefügt worden ist.

Tabelle 54: Konstruktoren
Konstruktor Verwendung
Label()

Label(Icon)

Label(String)

Label(String, Icon)

Label(String, String)

Erzeugt ein Label.

Der anzuzeigende Text bzw. das anzuzeigende Icon kann wahlweise schon über den Konstruktor oder auch nachträglich über die Methoden setText(), setTextFrom() bzw. setIcon() spezifiziert werden. Wobei im Konstruktor die Spezifikation von Texten immer indirekt, d. h. über einen Pfad (Logischer Datentyp oder Stringtable) erfolgt.

Die Signaturen mit zwei Parametern erlauben zusätzlich die Zuweisung einer GUID zu dem Label (die Signaturen ohne GUID sind „deprecated“).

 

Tabelle 55: Visuelles Erscheinungsbild
Methode Verwendung
LEFT

RIGHT

TOP

BOTTOM

CENTER

getHorizontalAlignment()

setHorizontalAlignment(
int)

getVerticalAlignment()

setVerticalAlignment(int)

Horizontale bzw. vertikale Ausrichtung von Text bzw- Icon innerhalb des Labels abfragen, setzen oder ändern  (Label.LEFT, Label.CENTER und Label.RIGHT) bzw. (Label.TOP, Label.CENTER und Label.BOTTOM).

Diese Einstellungen kommen nur dann zum Tragen, wenn das Label tatsächlich größer ist als der anzuzeigende Text/Icon.

Die Eigenschaften horizontal- bzw. verticalAligment sollten nicht mit den (von VisualElement geerbten) Eigenschaften alignmentX bzw. alignmentY verwechselt werden. Letztere dienen als Hinweise für (bestimmte) Layout-Manager und beeinflussen nicht die Ausrichtung innerhalb des Labels, sondern die Ausrichtung von verschiedenen Elementen untereinander. Im Allgemeinen müssen beide Arten von Eigenschaften aufeinander abgestimmt sein, um eine gewünschte Ausrichtung zu erzielen.

LEFT

RIGHT

TOP

BOTTOM

CENTER

getHorizontalTextPosition()

setHorizontalTextPosition(int)

getVerticalTextPosition()

setVerticalTextPosition(
int)

Positionierung des Textes (relativ zu dem Icon) abfragen/festlegen.

Wenn ein Label sowohl ein Icon als auch einen Text besitzt, so spezifizieren die Eigenschaften horizontal- und verticalTextPosition, ob der Text „rechts“, „links“, „über“, „unter“ oder „mittig“ zu dem Icon platziert werden soll.

getIconTextGap()

getIconTextGap(int)

Abstand zwischen Text und Icon abfragen/festlegen.

Wenn ein Label sowohl ein Icon als auch einen Text besitzt, so werden diese durch den spezifizierten Abstand (Pixel) getrennt.

NONE

HORIZONTAL

VERTICAL

getLineOrientation()

setLineOrientation(int)

Führungslinie abfragen, setzen oder ändern.

Unterstützt werden:

• „Ohne Führungslinie“ (Label.NONE),

• „Linie am unteren Rand“ (Label.HORIZONTAL) und

• „Linie am linken Rand“ (Label.VERTICAL).

Diese Eigenschaft ist von Bedeutung, wenn das Label als Beschriftung für ein anderes Element dienen soll (siehe Eigenschaft labelFor).

 

Tabelle 56: Visuelles Erscheinungsbild
Methode Verwendung
setIcon(Icon) Legt das Icon fest, das das Label anzeigen soll.
setDisabledIcon(Icon) Erlaubt die Verwendung eines speziellen (zusätzlichen) Icons für den Zustand enabled==false.

Wenn kein spezielles Icon spezifiziert ist, dann wird die Standarddarstellung für diesen Zustand benutzt.

 

Tabelle 57: Anwendungsunterstützung
Methode Verwendung
getUrl()

setUrl(String)

Hyperlink (URL) abfragen/setzen.

Erlaubt die Verknüpfung des Labels mit einer URL. Klickt der Benutzer auf dieses Label (Text und/oder Icon) wird die spezifizierte URL in einem separaten Fenster geöffnet.

setLabelFor(
VisualElement)
Legt fest, dass dieser Label als Beschriftung für ein anderes VisualElement dienen soll.

Das Verhalten und Aussehen dieser beiden miteinander verbundenen Elemente ist dann ähnlich zu den Feldern (mit integriertem Label).

 

Tabelle 58: Metadatenunterstützung
Methode Verwendung
getText()

setText(String)

setTextFrom(String)

setTextFrom(String, String[])

Text für Label abfragen, setzen oder ändern.

Bei Elementen, die mithilfe von Metadaten (Logischer Datentyp oder Stringtable) erzeugt werden, wird dieser Wert automatisch vorbelegt. Wenn kein Text erwünscht ist, kann der Text mit setText(null) unterdrückt werden.

 

3.4.2 Button

Die Klasse com.cisag.pgm.gui.Button dient der Anzeige von Schaltflächen, so genannter „Buttons“. Das „Drücken“ einer solchen Schaltfläche durch den Benutzer, stellt für die zugehörige Anwendung ein Ereignis dar. Im Allgemeinen wird in der Anwendung durch dieses Ereignis eine Aktion (Action) angestoßen (siehe 3.11.1 Action, ActionListener).

Die Erzeugung und Initialisierung eines Buttons erfolgt wie bei den Feldern über Metadaten, wobei die Metadaten für Buttons nicht, wie bei den Feldern, aus logischen Datentypen oder DataDescriptions kommen, sondern aus Actions.

Der Semiramis-Styleguide sieht verschiedene Arten bzw. Stile für Buttons vor. Neben den üblichen (Push-)Buttons stehen auch Buttons mit (Drop-Down) Menüs zur Verfügung. Die Auswahl einer bestimmten Art bzw. eines Stils erfolgt über den Konstruktur. Je nachdem, ob eine einzelne Action oder eine Liste von Actions übergeben wird, wird ein einfacher (Push-) Button bzw. ein Button mit (Drop-Down) Menü erstellt. Darüberhinaus lässt sich das Erscheinungsbild über den Parameter „type“ an den jeweiligen Kontext anpassen.

Typ Beschreibung
Button.TEXT_BUTTON Es wird nur der Text (Label) aus der Action verwendet.

Der Button verwendet einen Standardrahmen.

Beispiel: „OK“ und „Abbrechen“ in typischen Dialogen.

Button.ICON_BUTTON Es wird nur das (kleine) Icon aus der Action verwendet.

Der Button verwendet einen speziellen Rahmen mit „roll-over“-Effekt.

Beispiel: Wird in Semiramis praktisch nicht verwendet.

Button.HEADER_BUTTON Es wird nur das (kleine) Icon aus der Action verwendet.

Der Button verwendet einen speziellen Rahmen mit „roll-over“-Effekt.

Beispiel: Praktisch alle Buttons, die in „normalen“ CoolBars verwendet werden.

Button.COOLBAR_BUTTON Wie Button.HEADER_BUTTON, nur das hier das „große“ Icon aus der Action verwendet wird.

Beispiel: Praktisch alle Buttons, die in der Standard-Symbolleiste verwendet werden.

Button.MENU_BUTTON Spezieller Typ für Menüeinträge.

Es werden (wenn vorhanden) sowohl Icon als auch Text aus der Action verwendet.

Beispiel: Kontextmenüs.

Button.SMART_BUTTON Spezieller Typ für Menüeinträge von „SmartButtons“.

Es werden (wenn vorhanden) sowohl Icon als auch Text aus der Action verwendet.

Hinweis:
Die „SmartButtons“ haben selbst keinen besonderen Typ, sondern nur ihre (intern erzeugten) Menüeinträge.

 

Die Buttonklasse stellt mehrere Konstruktoren mit unterschiedlichen Signaturen zur Verfügung. Es empfiehlt sich den Konstruktor Button(Action action, int type, boolean showIcon, boolean showText) zu verwenden. Anhand des Action Objekts wird der Button komplett initialisiert:

  • Icons (abhängig von „showIcon“, Größe abhängig vom Parameter „type“)
  • Beschriftung (abhängig von „showText“)
  • ToolTip
  • Shortcut
  • Direkthilfe
  • enabled/disabled

Die Metadaten zu Actions werden normalerweise im Repository als Entwicklungsobjekt „Action“ angelegt und auch dort gepflegt.

Der Button wird auch automatisch aktualisiert, wenn sich die Eigenschaften der Action ändern.

Wenn nicht nur eine einzelne Action, sondern eine ActionList bzw. eine Action mit „Subactions“ im Konstruktor spezifiziert wurde, so wird der Button mit einer geteilten Schaltfläche ausgestattet. Über die linke Seite kann die Default-Action direkt ausgelöst werden, über die rechte Seite kann ein (Drop-Down)-Menü mit allen Actions geöffnet werden. Diese Art von Button wird auch „SmartButton“ genannt. Ein ähnliche Art von Button wird durch die Klasse MenuButton bereitgestellt (siehe 3.4.2.2 MenuButton).

Die Abbildung stellt einen „SmartButton“ im Normalzustand (oben), beim Überfahren mit der Maus (Mitte) und mit aufgeklappten Menü dar. Typisch sind das Icon und der Pfeil (nach unten gerichtet) rechts daneben. Das Icon symbolisiert die jeweils aktuelle Default-Action.

  • Button vom Typ SMART_BUTTON (mitte: mouse over, unten: aufgeklappt)

Das Drop-Down-Menü kann durch Klicken auf den Pfeil geöffnet werden. Die in der Liste angebotenen Aktionen können direkt ausgelöst werden, wenn man sie anklickt oder die „ENTER“ Taste betätigt.

Mit den Parametern showIcon bzw. showText im Konstruktor der Klasse kann vom Entwickler selbst bestimmt werden, ob Icon, Text oder beide sichtbar sind.

Die Buttonklasse verfügt über eine Methode setIcon(Icon ic). Mit dieser können extern Icons gesetzt werden, welche die aus dem Action-Objekt gelieferten überschreiben.

3.4.2.1 ToggleButton

Ein ToggleButton unterscheidet sich von einem Button dadurch, dass er einen von zwei Zuständen „selektiert“ (ToggleButton.SELECTED) bzw. „nicht selektiert“ (ToggleButton.DESELECTED) einnehmen kann, die visuell unterschiedlich sind. Der selektierte Zustand wird typischerweise als „gedrückter“ Button dargestellt.

Die folgende Abbildung stellt einen ToggleButton mit den Zuständen nicht selektiert (oben) und selektiert (unten) dar. Das mittlere Bild zeigt den Button beim Überfahren mit dem Mauszeiger.

  • ToggleButton (oben: nicht selektiert, mitte: mouse over, unten: selektiert)

Die Instanzierung eines ToggleButton erfolgt ähnlich wie für Elemente der Elternklasse Button. Dem Konstruktor ToggleButton(String guid, Action action, int type, boolean showIcon, boolean showText) müssen die GUID, die Action, der Buttontyp sowie die Schalter zum Anzeigen von Icon und Text übergeben werden. Bei Nutzung der Konstruktoren ohne Angabe des Typs wird defaultgemäß Button.TEXT_BUTTON angenommen.

Den Anfangsstatus des ToggleButtons bestimmt das Action Object über action.getState(). Jede Zustandsänderung wird an die Action weitergegeben, die ihrerseits ihre registrierten ActionListener benachrichtigt.

Über die Methode getState() kann der aktuelle Status erfragt werden. Umgekehrt ist über setState(int state) ein Zustandswechsel möglich.

3.4.2.2 MenuButton

Bei MenuButtons handelt es sich eigentlich um Drop-Down Menüs. Ihr Aussehen wurde aber so gestaltet, dass sie zusammen mit anderen Buttons in Symbolleisten (siehe 3.7.1 CoolBar) verwendet werden können. Die Schaltfläche des MenuButtons dient nur dazu das Drop-Down Menü zu öffnen (dies wird durch einen kleinen Pfeil angedeutet).

  • MenuButton (unten mit geöffnetem Menü)

Wie alle Buttons bezieht auch der MenuButton seine Icons, Texte und Shortcuts über entsprechende Actions. Allerdings verwendet der MenuButton dazu mehrere Actions. Eine Action ist dem MenuButton selbst zugeordnet, die anderen Actions definieren seine Menueinträge. Organisiert bzw. bereitgestellt werden diese Actions über die Hilfsklasse com.cisag.pgm.gui.ActionList (siehe 3.11.2 ActionList). Diese Klasse ist von com.cisag.pgm.gui. Action abgeleitet und spezifiziert in dieser Eigenschaft die Eigenschaften (Icon, Text, Shortcut und Direkthilfe) für den MenuButton selbst. Die mit add registrierten „Sub-“Actions definieren die entsprechenden Eigenschaften der einzelnen Menüeinträge.

Der MenuButton ist eng verwandt mit dem so genannten „SmartButton“ (siehe 3.4.2 Button). Der Hauptunterschied liegt in der Tatsache, dass der MenuButton keine „Default-Action“ besitzt und sich auch nicht die letzte Auswahl des Benutzers merken kann. Die Schaltfläche des MenuButtons ist daher auch nicht geteilt.

Das Beispiel in 4.2.1 MenuButton zeigt wie ein MenuButton erzeugt und in eine Symbolleiste eingefügt werden kann.

3.4.2.3 CheckBox

Die Klasse com.cisag.pgm.gui.CheckBox ist eine Ableitung von com.cisag.pgm.gui.BooleanField (siehe 3.5.7 BooleanField) und erweitert die Klasse insofern, als ein Action Objekt definiert werden kann, welches bei Zustandsänderung ausgelöst wird.

Die Action wird der CheckBox im Konstruktor CheckBox (String guid, String path, Action action) neben GUID und Pfad übergeben.

3.4.2.4 RadioButton

Die Klasse com.cisag.pgm.gui.RadioButton stellt eine Ableitung der Klasse com.cisag.pgm.gui.ToggleButton dar und unterscheidet sich von dieser wesentlich in der grafischen Repräsentation ihrer Elemente. Ein RadioButton hat das typische Aussehen eines unter Windows bekannten Optionsfeldes, welches aus einem Auswahlknopf und einer Beschriftung besteht (vgl. Abbildung 3-34). Der RadioButton kennt wie der Togglebutton zwei Status.

Instanzen vom Typ RadioButton erhält man mit dem Konstruktor RadioButton(String guid, Action action), der eine GUID und ein Action Object benötigt. Die Steuerung der unterschiedlichen Zustände sowie die Propagierung der Ereignisse bei Änderung wird von der Elternklasse übernommen.

3.4.3 ListBox

Für die Präsentation einer einfachen Liste steht die Klasse com.cisag.pgm.gui.ListBox zur Verfügung. Eine Instanz von ListBox erhält man über den Konstruktor ListBox(String guid).

Das Füllen der Liste findet nach ihrer Instanziierung mit den Methoden add(String text) bzw. add(String text, Object dataObject) statt. Der als „text“ übergebene String wird in der Liste angezeigt. Das „dataObject“ wird dabei mit dem Eintrag verbunden. Ist kein „dataObject“ gesetzt, wird der Textstring selbst als solches angenommen. Die Liste erhält ihre Einträge in der Reihenfolge der Aufrufe der add()-Methode. Mit getDataObjectAt(int index) wird der Eintrag mit dem betreffenden Index zurückgeliefert. Ist ein solcher nicht vorhanden, liefert die Methode null zurück. Die Methode clear() löscht den gesamten Listeninhalt.

In der Voreinstellung erlaubt die Liste eine Auswahl mehrerer Items (MULTIPLE_INTERVAL_SELECTION). Eine Änderung der Selektionsart erfolgt über die Methode setSelectionMode(int selectionMode), wobei für SINGLE_SELECTION der Wert „0“, für SINGLE_INTERVAL_SELECTION der Wert „1“ und für MULTIPLE_INTERVAL_SELECTION der Wert „2“ übergeben werden muss.

Den oder die selektierten Einträge erhält man mit getSelectedDataObjects() zurück. Mit der Methode setSelectedDataObject(Object dataObject) kann eine Selektion in der Liste veranlasst werden. Der Aufruf clearSelection() löscht die aktuelle Selektion.

ListBox-Objekte unterstützen den Scrolling-Mechanismus und fügen am rechten Rand einen Scrollbalken ein, falls  es erforderlich ist. Die Methode setVisibleRowCount(int visibleRowCount) ermöglicht es, der Liste über die Angabe der Anzahl der Zeilen eine bevorzugte sichtbare Höhe zuzuteilen.

3.5 Felder

3.5.1 TextField

Elemente vom Typ com.cisag.pgm.gui.TextField dienen zur Ein- und Ausgabe von einfachen (einzeiligen) Zeichenketten.

Zur Erzeugung eines TextField Objektes übergibt man dem Konstruktor die GUID und den Pfad für die Metadaten. Defaultgemäß sind Textfelder „enabled“, d. h. bedienbar. Die Methodenaufrufe setEditable(false) bzw. setEnabled(false) versetzen die Felder in den Zustand „read only“ bzw. „disabled“. Sie sind dann nicht mehr eingabebereit. Nicht editierbare Felder sind weiterhin fokusierbar und ihr Inhalt kann z. B. in die Zwischenablage kopiert werden („Ctrl+C“).

Durch Wahl des entsprechenden Content Typs der Methode setContentType(int type) kann aus dem normalen Textfeld ein Feld zum Versenden von E-Mails entstehen. Hierfür muss der Methode der Wert TextField.CONTENT_TYPE_EMAIL übergeben werden. Beim Mausklick auf das Feld wird ein neues E-Mail-Clientfenster erzeugt, welches bereits mit der im Feld angegebenen Adressierung versehen ist.

Ähnlich entsteht ein URL-Feld, indem der Methode der Wert TextField.CONTENT_TYPE_URL übergeben wird. Das Feld öffnet bei Mausklick die angegebene URL in einem neuen Browserfenster.

Visualisierung und Verhalten von E-Mail und URL Feldern beim Überfahren mit der Maus entsprechen dem von Linkelementen.

Anhand der „CONTENT_TYPE“ Vorgabe aus der DataDescription kann ein Textfeld in den CONTENT_TYPE_ IDENTIFIER-Modus versetzt werden. Das bedeutet, dass der Inhalt des Feldes nur bestimmte Zeichen enthalten darf, nämlich nur solche, die für eine „ID“ zulässig sind. Diese sind: Großbuchstaben, Ziffern, Bindestrich „-“, Unterstich „_“ und Punkt „.“. Bei jeder Änderung des Feldinhalts wird dieser auf nicht erlaubte Zeichen hin überprüft und das Feld gegebenenfalls mit einer roten Meldungsecke versehen.

Das Eintippen nicht zulässiger Zeichen in „IDENTIFIER“-Felder wird verhindert. Außerdem erfolgt bei Eingabe von Kleinbuchstaben eine automatische Konvertierung nach Großbuchstaben. Mit der Tastenkombination „CTRL+ALT+F12“ kann die Eingabesperre aufgehoben sowie bei erneuter Betätigung wieder in Kraft gesetzt werden.

Felder im Selektionsmodus führen generell keine Prüfung auf „IDENTIFIER“-Zeichen durch. Auch eine Prüfung der Textlänge erfolgt nicht, selbst wenn dies der beim Feld gesetzte logische Datentyp vorsieht. Die Konvertierung von Kleinbuchstaben nach Großschreibung bleibt erhalten.

3.5.2 ExtendedTextField

Unter einem ExtendedTextField versteht man ein um einen nicht editierbaren Teil erweitertes Textfeld. Die Abbildung zeigt ein ExtendedTextField ohne (oberes Bild) bzw. mit Eingabefokus. Der beschreibende Textteil wird in hellgrauer Schrift rechts neben dem editierbaren dargestellt.

  • ExtendedTextField (unten: mit Eingabefokus).

Der Benutzer kann nur den editierbaren Text ändern. Die Beschreibung wird immer vom System über die Methode setDescription(String str) gesetzt.

Das ExtendedTextField kann (wie jedes Feld) mit einer Wertehilfe versehen werden.

ExtendedTextFields erwarten in ihrem Konstruktor, neben der GUID und dem Pfad, ein Flag „description“. Über dieses Flag wird gesteuert, ob das Feld den „Description“-Teil permanent oder nur als ToolTip anzeigt. Letzteres ist aber auch über setDescriptionAsTooltip(boolean enabled) steuerbar.

Wie das TextFeld unterstützt auch das ExtendedTextField den ContentType „CONTENT_TYPE_IDENTIFIER“.

3.5.3 MultiLineTextField

Für die Darstellung eines mehrzeiligen Textes steht die Klasse com.cisag.pgm.gui.MultiLineTextField zur Verfügung. Die Abbildung zeigt das Feld im editierbaren Zustand.

  • MultiLineTextField

Die Instanzierung des Feldes erfolgt in gewohnter Weise über den Konstruktor MultiLineTextField(String guid, String path). Über die Methoden setValue(String), setStringValue(String) bzw. setValueFromObject(Object) kann der Text gesetzt bzw. geändert werden den das Feld anzeigen soll. Die dazugehörigen „get()“-Methoden liefern den Inhalt zurück.

Der Anwendungsentwickler kann über die Angabe der Anzahl der sichtbaren Zeilen mit setVisibleRowCount(int visibleRowCount) entscheiden, welche Höhe das MultiLineTextField auf der Benutzeroberfläche bekommen soll. Der Default liegt bei 8 Zeilen. Erst wenn der Inhalt nicht innerhalb der sichtbaren Zeilen dargestellt werden kann, wird ein vertikaler Scrollbalken auf der rechten Seite des Feldes sichtbar.

Der Zeilenumbruch erfolgt stets automatisch. Ein horizontaler Scrollbar wird nicht angezeigt.

Eine spezielle Verwendung ist in folgender Abbildung zu sehen.

  • MultiLineTextField mit DialogButton

Das Feld zeigt rechts neben dem Label eine Raute, die beim Anklicken einen Dialog erscheinen lässt. Innerhalb des Dialogs wird der Inhalt bearbeitet, gegebenenfalls transformiert und dem Feld übergeben. Das Feld selbst ist in diesem Fall nicht editierbar.

In Anwendungen wird das MultiLineTextFeld häufig zusammen mit dem „National Language Support“ (NLS) verwendet. Ob der NL-Support verwendet werden soll, wird über die DataDescription festgelegt (LOCALIZATION_ENABLED == true).

3.5.4 EntityField

Die abstrakte Klasse EntityField (com.cisag.pgm.gui.EntityField), eine Ableitung von com.cisag.pgm.gui.ExtendedTextField, stellt die Basisklasse für alle EntityField-Varianten dar.

EntityFields dienen dazu, Business Entities auf dem Bildschirm zu repräsentieren, indem ihre Identifikation (fachlicher Schlüssel) im editierbaren und ihr beschreibender Text im nicht editierbaren Teil erscheinen.

Bei der Initialisierung werden alle EntityFields automatisch mit einer Link-Action (Hyperlink auf zugehörige Anwendung) und einer Popup-Action (Kontextmenü für das Entity) verknüpft. Gleiches gilt für die Wertehilfe.

Die Abbildung zeigt ein typisches EntityField (com.cisag.app.general.gui.CountryField) mit Wertehilfesymbol. Das Symbol ist nur sichtbar, wenn sich der Mauszeiger über dem Element befindet.

  • EntityField vom Typ CountryField

Die Erstellung (Implementierung) und Benutzung von EntityFields ist im „Programmierhandbuch“ beschrieben.

3.5.5 ValueSetField

Das ValueSetField dient der Ein- und Ausgabe von Daten, die auf dem Datentyp „ValueSet“ basieren. Bei einem ValueSet (vergleichbar mit einer Enumeration) ist der Wertebereich durch eine Menge von diskreten Werten (short) fest vorgegeben (im Repository definiert), für jeden Wert ist zudem ein Beschreibungstext definiert.

Im Standard-Modus kann der Benutzer über das ValueSetField genau einen Wert aus der Liste mit den möglichen Werten auswählen. Die Darstellung und das Verhalten des ValueSetFields entspricht dabei dem einer üblichen (nicht editierbaren) ComboBox. Für die Anzeige (im Feld und in der Auswahlliste) werden die Beschreibungstexte verwendet, als „Wert“ für getValue() und setValue() werden jedoch die short Werte des ValueSets benutzt.

Wenn das ValueSetField nicht als Pflichtfeld (required==true) konfiguriert ist, kann die aktuelle Auswahl über die Taste „Entf“ gelöscht, also das Feld geleert werden. In diesem Fall steht auch in der Auswahlliste ein zusätzlicher Eintrag mit der Bezeichnung „(leer)“ zur Auswahl, über den das Feld ebenfalls geleert werden kann.

  • ValueSetField (Standard-Modus).

ValueSetField Objekte werden über die Konstruktoren ValueSetField(String guid, String path) bzw. ValueSetField(String guid, String path, Action action) erzeugt. Zusätzlich kann der Entwickler eine Action registrieren, deren Listener benachrichtigt werden sollen, wenn sich der Wert im Feld geändert hat.

Zusätzliche Einträge können mithilfe der Methoden addValueSetItem(String externalName) bzw. addValueSetItem(short constantValue, String externalName) definiert/hinzugefügt werden.

Mithilfe von setVisibleValues(short[] constantValues, boolean originalSorting) lässt sich die Anzeige auf bestimmte Werte einschränken und/oder sortieren.

Im Standard-Modus verhalten sich die Methoden getValueAsObject bzw. setValueFromObject(Object) wie die Methoden getValue() bzw. setValue(short) und liefern bzw. ändern den ausgewählten Wert. Die Konstante ValueSetField.UNDEFINED repräsentiert dabei den Fall, dass nichts ausgewählt wurde.

Selektionsmodus

Im Selektionsmodus unterstützt das ValueSetField die Auswahl von mehr als einem Wert.

Auf der Oberfläche wird statt der ComboBox ein Popup-Fenster mit CheckBoxen verwendet. Da der Benutzer mehr als eine CheckBox auswählen kann, wird auch ein „OK“-Button benötigt, um die Auswahl abschließen zu können. Als Auswahlhilfe wird eine zusätzliche CheckBox „(Alle)“ bereitgestellt, über die alle Einträge mit einem Klick selektiert bzw. deselektiert werden können.

  • ValueSetField (Selektionsmodus).

Bei geschlossenem Fenster hängt die Anzeige in dem Feld davon ab, wieviele Einträge ausgewählt wurden. Wenn kein Eintrag ausgewählt wurde, dann erscheint dort „(Kein)“. Wenn genau ein Eintrag ausgewählt wurde, dann wird dieser angezeigt. Wenn alle Einträge ausgewählt wurden, dann erscheint dort „(Alle)“. In allen anderen Fällen erscheint „(Mehrfachauswahl)“.

Wenn es sich nicht um ein Pflichtfeld handelt, wird eine zusätzliche Checkbox „Sonstige“ ans Ende der Liste angehängt. Die Auswahl dieses Eintrags schließt bei Suchen insbesondere die Datensätze ein, die den Wert ValueSetField.UNDEFINED besitzen.

Hinweis:
Im Selektionsmodus bezieht sich die Eigenschaft „required“ (bzw. „Pflichtfeld“) nicht auf das ValueSetField, sondern auf die Daten, über die eine Suche erfolgen soll. Aus dieser Eigenschaft leitet das ValueSetField ab, welche Werte in den Daten vorkommen können. Bei required==true können nur die im ValueSet definierten Werte vorkommen, bei required==false kann dagegen auch der Wert ValueSetField.UNDEFINED vorkommen.

Eine leere Selektion ist generell nicht erlaubt („OK“-Button bleibt „disabled“). Der Aufruf von setValueFromObject(null) wird deshalb so umgesetzt, dass stattdessen alle Einträge selektiert werden. Über die Methode setNoneAllowed() kann dieses Verhalten geändert werden.

Im Selektionsmodus liefert die Methode getValueAsObject(), wie getSelection(), ein Array (short[]) mit den selektierten Werten zurück, oder null, wenn nichts selektiert ist.

Analog ist im Selektionsmodus bei der Methode setValueFromObject(Object), wie bei setSelection(Object), ebenfalls ein Array (short[]) mit den zu selektierenden Werten zu übergeben.

3.5.6 MultiValueSetField

Das MultiValueSetField ist eine Erweiterung des ValueSetFields (nur Selektionsmodus). Es erlaubt die Gruppierung von Einträgen einschließlich gruppenweiser Selektion/Deselektion. Die Darstellung der Auswahl im Popup-Fenster erfolgt als Baumstruktur, wie die folgende Abbildung zeigt.

  • MultiValueSetField

Die darzustellenden bzw. auswählbaren Gruppen werden jeweils über ein ValueSet definiert. Das Hinzufügen von Gruppen erfolgt über die Methode addValueSet(String path). Der Pfad spezifiziert einen logischen Datentyp (ValueSet) bzw. die zugehörige DataDescription.

Der Wert des Feldes, d. h. die jeweilige Auswahl, wird durch ein 2-dimensionales Array (short[][]) repräsentiert. Dieser Wert kann über die Methoden setValue(short[][]) bzw. setValueFromObject(Object) gesetzt werden. Wobei setValueFromObject(Object) zusätzlich auch eine Liste (java.util.List) mit short[] Objekten akzeptiert. Analog liefern getValue() ein 2-dimensionales Array (short[][]) und getValueAsObject() eine Liste (java.util.List) mit short[] Objekten zurück.

3.5.7 BooleanField

Das BooleanField unterscheidet zwischen zwei Darstellungsformen, die von der Eigenschaft „selectionMode“ abhängen.

Im Standard-Modus nutzt das Feld eine übliche „CheckBox“.

  • BooleanField (Standard-Modus)“

Wobei neben den Zuständen „selektiert“ und „nicht selektiert“ über die Methode setTriStateSupported(boolean triStateSupported) optional auch der Zustand „undefiniert“ freigeschaltet werden kann. Für diesen Zustand kann mit der Methode setUndefinedIcon(Icon icon) auch ein spezielles Icon definiert werden.

Mit den Methoden setValue(boolean), setValueFromObject(Object) bzw. setState(int) kann der Wert des BooleanFields gesetzt werden. Wobei true dem Wert BooleanField.SELECTED bzw. false dem Wert BooleanField.DESELECTED entspricht. Der Wert BooleanField.UNDEFINED kann nur über setValueFromObject(Object) bzw. setState(int) gesetzt werden. Die dazugehörigen get()-Methoden liefern den Zustand in entsprechender Form zurück.

Selektionsmodus

Im Selektionsmodus nutzt das BooleanField eine ComboBox-Darstellung.

  • BooleanField im Selektionsmodus

Welche Zustände das Feld im Selektionsmodus einnehmen kann, hängt von der Eigenschaft „required“ ab. Diese steht üblicherweise auf false, was bedeutet, dass drei Werte („ja“, „nein“, „ignorieren“) möglich sind. Durch den Aufruf der Methode setRequired(true) kann das Feld zum Pflichtfeld gemacht werden, in diesem Fall sind nur noch die Werte „ja“ und „nein“ zulässig.

Die Methoden set/getSelectionString() können im Selektionsmodus ebenfalls benutzt werden, um den Zustand des Feldes zu ändern bzw. abzufragen. Der Wert “true” entspricht „ja“, der Wert “false” entspricht „nein“ und der Wert null (bzw. ein leerer String) wird als „ignorieren“ interpretiert.

Die Methoden set/getValue() haben die gleiche Funktion wie im Standard-Modus.

3.5.8 RadioButtonGroup

Die Klasse com.cisag.pgm.gui.RadioButtonGroup dient, ähnlich wie das ValueSetField (siehe 3.5.5 ValueSetField), der Ein- und Ausgabe von Daten, die auf dem Datentyp „ValueSet“ basieren. Bei der RadioButtonGroup erfolgt die Anzeige bzw. die Auswahl eines Wertes jedoch über RadioButtons (siehe 3.4.2.4 RadioButton). Für jeden Wert aus dem ValueSet wird ein eigener RadioButton bereitgestellt. Wie in dem ValueSetField kann auch hier immer nur ein Wert ausgewählt sein.

Damit die RadioButtonGroup wie jedes andere Feld behandelt werden kann, ist sie von com.cisag.pgm.gui.Field abgeleitet.

Die RadioButtonGroup wird über ihren Konstruktor RadioButtonGroup(String guid, String path, Action changed, boolean horizontal) instanziert. Übergabeparameter sind eine GUID, ein Pfad und optional ein Action Objekt. Der Parameter horizontal legt fest, ob die Buttons in horizontaler (true) oder vertikaler (false) Richtung angeordnet werden sollen.

  • RadioButtonGroup

Die Definition der Radiobuttons, d. h. der Einträge in der RadioButtonGroup, erfolgt wie bei ValueSetFields über die DataDescription.

Ein Aufruf der Methode setSelectedIndex(int index) bei der RadioButtonGroup setzt den RadioButton mit dem angegebenen Index auf „selektiert“. Entsprechend liefert getSelectedIndex() den Index des selektierten Buttons zurück.

Wird im Konstruktor ein Action Objekt übergeben, so werden dessen Listener jedesmal benachrichtigt, wenn sich an der Auswahl etwas ändert. Bei dem registrierten Action-Objekt kann über getState() die aktuelle Auswahl erfragt bzw. das zugehörige „Data-Object“ (meist der Beschreibungstext) erfragt werden.

RadioButtons können der RadioButtonGroup auch direkt mit den Methoden add(short value, String text), add(String text) bzw. add(String text, Object dataObject) hinzugefügt werden.

Mithilfe von setVisibleValues(short[] constantValues, boolean originalSorting) lässt sich, wie bei dem ValueSetField, die Anzeige auf bestimmte Werte einschränken und/oder sortieren.

3.5.9 DecimalField

Die Klasse com.cisag.pgm.gui.DecimalField dient der Ein- und Ausgabe von Dezimalzahlen (com.cisag.pgm.datatype.CisDecimal). Die Klasse DecimalField ist ähnlich aufgebaut wie die IntegerField Klassen (siehe 3.5.11 ByteField, ShortField, IntegerField, LongField) und ist auch genauso zu verwenden.

Die Formatierung der Ausgabe erfolgt anhand der jeweiligen Benutzeinstellungen (z. B. Dezimaltrennzeichen, Tausendergruppierung,…).

Die Anzahl der Vor- bzw. Nachkommastellen, sowie Minimum- oder Maximumwerte werden aus der DataDescription übernommen. Wenn im Repository keine speziellen Angaben gemacht wurden, dann gelten folgende Standardwerte:

Default Einstellung Beschreibung
15 max. Anzahl Vorkommastellen
6 max. Anzahl der Nachkommastellen
2 min. Anzahl der Nachkommastellen

 

Der Wert des Feldes lässt sich mit getValue() oder getValueAsObject() abfragen bzw. mit setValue(CisDecimal) bzw. setValueFromObject(Object) ändern.

3.5.10 PercentField

Die Klasse com.cisag.pgm.gui.PercentField erlaubt die Ein- und Ausgabe von Zahlenwerten mit der Einheit Prozent. Editierbar ist jeweils nur die Dezimalzahl, während das Prozentzeichen unverändert rechts neben der Zahl erscheint.

Das Feld ist wie üblich über den Konstruktor unter Angabe einer GUID und eines Pfades zu erzeugen.

Über die Methoden setValue(CisDecimal) bzw. setValueFromObject(Object) kann dem Feld eine neue Dezimalzahl zugewiesen werden. Die Einheit Prozent bleibt dabei unberührt.

Die Methoden getValue() bzw. getValueAsObject() liefern die Dezimalzahl zurück. Mit getStringValue() erhält man eine Zeichenkette bestehend aus der Zahl mit angehängtem Prozentzeichen.

3.5.11 ByteField, ShortField, IntegerField, LongField

Für die Ein- und Ausgabe von Ganzzahlen steht für jeden primitiven Datentyp (byte, short, int, long) je eine von com.cisag.pgm.gui.Field abgeleitete Klasse zur Verfügung.

Die Instanziierung der Felder erfolgt über ihren jeweiligen Konstruktor, dem eine GUID sowie ein Pfad übergeben werden muss.

Die Methoden setValue() bzw. getValue() arbeiten mit dem Datentyp, der das entsprechende Feld charakterisiert. Der Funktion setValueFromObject(Object value) muss als Wert das zum Datentyp passende java.lang.Object (java.lang.Byte, java.lang.Short, java.lang.Integer, java.lang.Long) übergeben werden.

Den Feldwert als java.lang.Object liefert die Methode getValueAsObject() zurück.

Die Felder erlauben nur die Eingabe von numerischen, sowie Trenn- und Minuszeichen. Die Benutzereingabe wird nach dem Fokuswechsel geparst und hinsichtlich des für den jeweiligen Zahlentyp gültigen Wertebereichs überprüft. Bei Überschreiten des Bereichs erhält das Feld eine rote Ecke, die beim Anklicken eine Fehlermeldung erscheinen lässt (vgl. Kapitel 2.1.7 Meldungen).

Die Felder berücksichtigen die Einstellungen des Benutzers bezüglich der gewünschten Symbole für Minus- und Tausendergruppierung. Zudem kann in den Benutzereinstellungen auch definiert werden, ob negative Zahlen rot dargestellt werden sollen.

Die maximale Anzahl der Stellen wird der DataDescription entnommen. Wird keine Angabe gemacht, gelten die folgenden Defaulteinstellungen:

Typ Default „Max. Integer Digits“ Default „min./max. value“
BYTE 3 Byte.MIN_VALUE
Byte.MAX_VALUE
SHORT 5 Short.MIN_VALUE
Short.MAX_VALUE
INT 10 Integer.MIN_VALUE
Integer.MAX_VALUE
LONG 19 Long.MIN_VALUE
Long.MAX_VALUE

 

Die Benutzereingabe wird auf die maximale Anzahl der Stellen begrenzt, insofern, als bei Überschreitung die Tastatur gesperrt wird. Wenn über die Zwischenablage ein ungültiger Wert eingefügt wird, dann wird das Feld mit einer roten Meldungsecke versehen.

Der Entwickler hat bei numerischen Feldern die Möglichkeit im Repository einen Wertebereich (Minimum, Maximum) zu definieren, der vom Wert des Feldes nicht über- bzw. unterschreiten werden darf.

3.5.12 CisDateField

Datumswerte und Zeitpunkte werden in Semiramis durch die Klasse com.cisag.pgm.datatype.CisDate repräsentiert. Diese Klasse speichert nicht nur das jeweilige Datum bzw. den Zeitpunkt, sondern auch die Zeitzone, die zum Zeitpunkt der Erfassung verwendet wurde. Somit kann der Wert später exakt so angezeigt werden, wie er erfasst wurde — auch wenn dies durch einen anderen Benutzer in einer anderen Zeitzone erfolgen sollte.

Die Klasse CisDateField dient der Ein- und Ausgabe von CisDate basierten Datumswerten bzw. Zeitpunkten. Der im Kontruktor übergebene Pfad muss zu einem logischen Datentyp gehören, der von einem der folgenden Datentypen abgeleitet wurde:

  • cisag.pgm.datatype.CisObjectDate
  • cisag.pgm.datatype.CisAttributeDate
  • cisag.pgm.datatype.CisObjectDateUntil
  • cisag.pgm.datatype.CisAttributeDateUntil
  • cisag.pgm.datatype.CisObjecTimeStamp
  • cisag.pgm.datatype.CisAttributeTimeStamp

Die ersten vier Datentypen spezifizieren Datumswerte, die letzten beiden Zeitpunkte. Die Unterschiede zwischen CisObject* und CisAttribute* betreffen allein die Repräsentation auf der Datenbank[9] und sind für das Feld nicht weiter relevant. Die durch „Until“ gekennzeichneten Datumswerte dienen dem Spezialfall, dass ein Datum als obere Intervallgrenze verwendet werden soll[10].

In der aus dem logischen Datentyp erzeugten DataDescription[11] werden die Datumswerte durch die Typen Variant.LOCAL_DATE bzw. Variant.LOCAL_DATE_UNTIL repräsentiert und alle Zeitpunkte als Variant.LOCAL_TIMESTAMP. Dieser Typ legt dann für das Feld fest, wie CisDate Objekte behandelt werden sollen.

In der Standardeinstellung zeigt das CisDateField die Zeitzone eines CisDate nur an, wenn sie sich von dem aktuellen Kontext unterscheidet. Selbst dann ist sie nicht editier- bzw. änderbar. Über die Methode setTimeZoneEditable() kann das Feld jedoch so konfiguriert werden, dass die Zeitzone durch den Benutzer geändert werden kann.

Im Unterschied zu vielen anderen Feldern benötigt das CisDateField eine explizite Initialisierung. Über den Aufruf von setValue() muss dem Feld ein CisDate Objekt mit einer gültigen Zeitzone (GUID) übergeben werden. Fehlt diese Initialisierung, kann das Feld bei getValue() kein CisDate Objekt erzeugen und wirft deshalb eine java.lang.IllegalStateException. Aus dem selben Grund ist es auch nicht erlaubt, bei dem Feld den Wert einfach auf null zu setzen. Mithilfe der Klasse com.cisag.pgm.datatype.CisDateUtility können geeignete CisDate Objekte erzeugt werden. Die Methode createUndefinedCisDate(byte[] timeZoneGuid) liefert beispielsweise ein CisDate Objekt zurück, mit dem ein CisDateField Feld initialisiert bzw. wieder geleert werden kann. Welche Zeitzone dabei zu benutzen ist, hängt von dem jeweiligen Anwendungsfall ab. Für den Fall, dass die Zeitzone dem aktuellen Anwendungskontext entsprechen soll, kann sie über:

CisCalendar cisCalendar =
CisEnvironment.getInstance().getContext().
getCisCalendar();

byte[] tzguid = cisCalendar.getTimeZoneGuid()

ermittelt werden.

Eine weitere Besonderheit an dem Feld ist die Behandlung von Prüfungen und Meldungen. Die Prüfung der Eingaben muss explizit durch die jeweilige Anwendung erfolgen bzw. angestoßen werden. Die Anwendung kann (und sollte) dabei auf die Hilfsklasse com.cisag.pgm.util.RepositoryValidation zurückgreifen, die hierfür entsprechende Methoden bereitstellt. Damit Fehler möglichst exakt den jeweiligen Teildaten (d.h. Datum, Uhrzeit, Zeitzone) zugeordnet und visualisiert werden können, verwendet das Feld zusätzliche „MessageIds“ für seine Teilfelder. Über die Hilfsklassen CisDateUtility bzw. CisTimeStampUtility können diese generischen „MessageIds“ abgefragt werden.

3.5.12.1 CisDateField API

Die folgenden Tabellen zeigen die wichtigsten bzw. meistgenutzten Methoden von CisDateField (eine vollständige Liste bzw. detaillierte Beschreibungen sind in der JavaDoc-Dokumentation von CisDateField zu finden):

Tabelle 59: Konstruktoren
Konstruktor Verwendung
CisDateField(String, String)

CisDateField(String, String, boolean)

 

Erzeugt ein CisDateField.

Als Parameter sind GUID und Pfad (logischer Datentyp) zu übergeben. Optional kann festgelegt werden, dass das Feld ausschließlich zur Anzeige von Daten verwendet wird (z. B. in Listen).

 

Tabelle 60: Datenzugriff
Methode Verwendung
getValue()

setValue(CisDate)

Aktuellen Wert des Feldes abfragen oder ändern.

Wie bei allen Feldern, stehen auch noch die von der Elternklasse Field geerbten Methoden getValueAsObject() und setValueFromObject() zur Verfügung.

 

Tabelle 61: Anwendungsunterstützung
Methode Verwendung
getSelectionMode()

setSelectionMode(boolean)

Wird von dem CisDateField nicht unterstützt. Hierzu steht ein spezielles Feld zur Verfügung: CisDateSelectionField.
isTimeZoneEditable()

setTimeZoneEditable(
boolean)

Legt fest, ob die Zeitzone durch den Benutzer geändert werden kann oder nicht.
setTimeOutputFormatPattern(short) Über diese Methode kann festgelegt werden, ob Sekunden bzw. Millisekunden immer angezeigt werden sollen oder nur wenn sie ungleich „0“ sind.

 

3.5.13 CisPointInTimeField

Dieses Feld dient der Ein- und Ausgabe von Terminen, wobei als „Genauigkeit“ für einen Termin eine Millisekunde, ein Tag, eine (Kalender-)Woche, ein Monat, ein Quartal oder ein Jahr gewählt werden kann.

Hinweis:
Die hier beschriebene Klasse stellt lediglich die Basisfunktionalität bereit. Typische Semiramis Anwendungen sollten die Klasse PointInTimeField aus dem Package com.cisag.app.general.gui verwenden.

Die technische Realisierung eines Termins erfolgt durch das Interface com.cisag.pgm.datatype.CisPointInTime welches einen Termin über folgende Eigenschaften definiert:

  • Calendar (CisCalendar)
  • Accuracy (Accuracy)
  • Value (String)
  • Offset (String)
  • Timestamp (util.Date)
  • Precision (byte[])

Ein Termin bezieht sich grundsätzlich auf einen Kalender, da erst durch diesen festgelegt wird, wann ein Tag oder eine Woche beginnt. Durch „Accuracy“ wird die Genauigkeit eines Termins spezifiziert, also beispielsweise tagesgenau oder wochengenau. Über „Value“ läßt sich der Wert in einer normalisierten Textform abfragen. Die Eigenschaft „Offset“ erlaubt eine Verschiebung zwischen der externen Darstellung und dem intern gespeicherten Wert. Ein wochengenauer Termin mit Offset „5 Tage“ würde beispielsweise dazu führen, dass als intern verwendeter Bezugspunkt nicht der Montag (0:00 Uhr), sondern der Sonnabend (0:00 Uhr) der betreffenden Woche genutzt würde. Der Offset kann wie der Wert (Value) in normalisierter Textform abgefragt werden. Der Wert des internen Bezugspunkts wird durch die Eigenschaft „Timestamp“ repräsentiert. Die Eigenschaft „Precision“ liefert die GUID des zur Speicherung von „Accuracy“ und „Offset“ verwendeten Business Objects zurück.

Wie das CisDateField (siehe 3.5.12 CisDateField) benötigt auch das CisPointInTimeField eine explizite Initialiserung. Die Initialisierung erfolgt über den Aufruf von setValue(). Fehlt diese Initialisierung, kann das Feld bei getValue() kein CisPointInTime Objekt erzeugen und wirft deshalb eine java.lang.IllegalStateException. Aus dem selben Grund ist es auch nicht erlaubt, bei dem Feld den Wert einfach auf null zu setzen. Mithilfe der Klasse com.cisag.pgm.datatype.CisPointInTimeUtility können geeignete CisPointInTime Objekte erzeugt werden. Die Methode createUndefinedCisPointInTimeMutable(CisCalendar calendar, short accuracy, String offset, byte[] precision) liefert beispielsweise ein CisPointInTime Objekt zurück, mit dem ein CisPointInTimeField Feld initialisiert bzw. wieder geleert werden kann. Welcher Kalender dabei zu benutzen ist, hängt von dem jeweiligen Anwendungsfall ab. Für den Fall, dass der Kalender dem aktuellen Anwendungskontext entsprechen soll, kann dieser über:

CisCalendar cisCalendar =
CisEnvironment.getInstance().getContext().
getCisCalendar();

ermittelt werden.

Auch bezüglich Prüfungen und Meldungen verhält sich das  CisPointInTimeField wie das CisDateField. Die Prüfung der Eingaben muss explizit durch die jeweilge Anwendung erfolgen bzw. angestoßen werden. Die Anwendung kann (und sollte) dabei auf die Hilfsklasse com.cisag.pgm.util.RepositoryValidation zurückgreifen, die hierfür entsprechende Methoden bereitstellt.

3.5.13.1 CisPointInField API

Die folgenden Tabellen zeigen die wichtigsten bzw. meistgenutzten Methoden von CisPointInTimeField (eine vollständige Liste bzw. detaillierte Beschreibungen sind in der JavaDoc-Dokumentation von CisPointInTimeField zu finden):

Tabelle 62: Konstruktoren
Konstruktor Verwendung
CisPointInTimeField(
String, String)

CisPointInTimeField(
String, String, boolean)

Erzeugt ein CisPointInTimeField.

Als Parameter sind GUID und Pfad (logischer Datentyp) zu übergeben. Optional kann festgelegt werden, dass das Feld ausschließlich zur Anzeige von Daten verwendet wird (z. B. in Listen).

 

Tabelle 63: Datenzugriff
Methode Verwendung
getValue()

setValue(CisPointInTime)

Aktuellen Wert des Feldes abfragen oder ändern.

Wie bei allen Feldern, stehen auch noch die von der Elternklasse Field geerbten Methoden getValueAsObject() und setValueFromObject() zur Verfügung.

 

3.5.14 TimeStampField

Das TimeStampField dient zur Ein- und Ausgabe von java.util.Date basierten Zeitpunkten (Timestamps). Diese Art von Zeitpunkten wird überwiegend von Systemanwendungen benutzt, z. B. als Zeitstempel in Änderungs- oder Meldungsprotokollen. Die vom TimeStampField angezeigten Datums- bzw. Zeitwerte beziehen sich immer auf die Zeitzone aus dem aktuellen Anwendungskontext[12].

Der im Kontruktor übergebene Pfad muss zu einem logischen Datentyp gehören, der von dem logischen Datentyp „com.cisag.pgm.datatype.TimeStamp“ abgeleitet wurde bzw. „Zeitstempel“ als primitiven Datentyp verwendet. In der aus dem logischen Datentyp erzeugten DataDescription werden die Datumswerte durch den Typ Variant.TIMESTAMP repräsentiert.

Wie das CisDateField (siehe 3.5.12 CisDateField) benötigt auch das TimeStampField eine explizite Initialiserung. Die Initialisierung erfolgt über den Aufruf von setValue(). Fehlt diese Initialisierung, kann das Feld bei getValue() kein Date Objekt erzeugen und wirft deshalb eine java.lang.IllegalStateException. Aus dem selben Grund ist es auch nicht erlaubt, bei dem Feld den Wert einfach auf null zu setzen. Mithilfe der Klasse com.cisag.pgm.datatype.CisTimeStampUtility können geeignete Date Objekte erzeugt werden. Die Konstante UNDEFINED_TIME_STAMP definiert beispielsweise ein Date Objekt, mit dem ein TimeStampField Feld initialisiert bzw. wieder geleert werden kann.

Auch bezüglich Prüfungen und Meldungen verhält sich das  TimeStampField wie das CisDateField. Die Prüfung der Eingaben muss explizit durch die jeweilge Anwendung erfolgen bzw. angestoßen werden. Die Anwendung kann (und sollte) dabei auf die Hilfsklasse com.cisag.pgm.util.RepositoryValidation zurückgreifen, die hierfür entsprechende Methoden bereitstellt. Damit Fehler möglichst exakt den jeweiligen Teildaten (d.h. Datum, Uhrzeit) zugeordnet und visualisiert werden können, verwendet das Feld zusätzliche „MessageIds“ für seine Teilfelder. Über die Hilfsklasse CisTimeStampUtility können diese generischen „MessageIds“ abgefragt werden.

3.5.14.1 TimeStampField API

Die folgenden Tabellen zeigen die wichtigsten bzw. meistgenutzten Methoden von TimeStampField (eine vollständige Liste bzw. detaillierte Beschreibungen sind in der JavaDoc-Dokumentation von TimeStampField zu finden):

Tabelle 64: Konstruktoren
Konstruktor Verwendung
TimeStampField(String, String)

TimeStampField(String, String, boolean)

 

Erzeugt ein TimeStampField.

Als Parameter sind GUID und Pfad (logischer Datentyp) zu übergeben. Optional kann festgelegt werden, dass das Feld ausschließlich zur Anzeige von Daten verwendet wird (z.B. in Listen).

 

Tabelle 65: Datenzugriff
Methode Verwendung
getValue()

setValue(java.util.Date)

Aktuellen Wert des Feldes abfragen oder ändern.

Wie bei allen Feldern stehen auch noch die von der Elternklasse Field geerbten Methoden getValueAsObject() und setValueFromObject() zur Verfügung.

 

Tabelle 66: Anwendungsunterstützung
Methode Verwendung
getSelectionMode()

setSelectionMode(boolean)

Wird von dem TimeStampField nicht unterstützt. Hierzu steht ein spezielles Feld zur Verfügung: CisDateSelectionField.

 

3.5.15 TimeOfDayField

Das TimeOfDayField dient zur Ein- und Ausgabe von Uhrzeiten. Der Datentyp für „value“ ist java.util.Date, wobei als Datum immer der 1.1.1970 zu verwenden ist, d.h. die Uhrzeit wird einfach als „Millisekunden seit Mitternacht“ gespeichert.

Der im Kontruktor übergebene Pfad muss zu einem logischen Datentyp gehören, der von dem logischen Datentyp „com.cisag.pgm.datatype.TimeOfDay“ abgeleitet wurde bzw. „Zeitstempel“ als primitiven Datentyp verwendet. In der aus dem logischen Datentyp erzeugten DataDescription werden die Datumswerte durch den Typ Variant.TIMESTAMP repräsentiert.

Wie das CisDateField (siehe 3.5.12 CisDateField) und TimeStampField (siehe 3.5.14 TimeStampField) benötigt auch das TimeOfDayField eine explizite Initialiserung. Die Initialisierung erfolgt über den Aufruf von setValue(). Fehlt diese Initialisierung, kann das Feld bei getValue() kein Date Objekt erzeugen und wirft deshalb eine java.lang.IllegalStateException. Aus dem selben Grund ist es auch nicht erlaubt, bei dem Feld den Wert einfach auf null zu setzen. Mithilfe der Klasse com.cisag.pgm.datatype.CisTimeStampUtility können geeignete Date Objekte erzeugt werden. Die Konstante UNDEFINED_TIME_STAMP definiert beispielsweise ein Date Objekt, mit dem ein TimeOfDayField Feld initialisiert bzw. wieder geleert werden kann.

Auch bezüglich Prüfungen und Meldungen verhält sich das  TimeOfDayField wie das CisDateField. Die Prüfung der Eingaben muss explizit durch die jeweilge Anwendung erfolgen bzw. angestoßen werden. Die Anwendung kann (und sollte) dabei auf die Hilfsklasse com.cisag.pgm.util.RepositoryValidation zurückgreifen, die hierfür entsprechende Methoden bereitstellt.

3.5.15.1 TimeOfDayField API

Die folgenden Tabellen zeigen die wichtigsten bzw. meistgenutzten Methoden von TimeOfDayField (eine vollständige Liste bzw. detaillierte Beschreibungen sind in der JavaDoc-Dokumentation von TimeOfDayField zu finden):

Tabelle 67: Konstruktoren
Konstruktor Verwendung
TimeOfDateField(String, String)

TimeOfDateField(String, String, boolean)

 

Erzeugt ein TimeOfDayField.

Als Parameter sind GUID und Pfad (logischer Datentyp) zu übergeben. Optional kann festgelegt werden, dass das Feld ausschließlich zur Anzeige von Daten verwendet wird (z. B. in Listen).

 

Tabelle 68: Datenzugriff
Methode Verwendung
getValue()

setValue(java.util.Date)

Aktuellen Wert des Feldes abfragen oder ändern.

Wie bei allen Feldern stehen auch noch die von der Elternklasse Field geerbten Methoden getValueAsObject() und setValueFromObject() zur Verfügung.

 

Tabelle 69: Anwendungsunterstützung
Methode Verwendung
getSelectionMode()

setSelectionMode(boolean)

Wird von dem TimeOfDayField nicht unterstützt.
setTimeOutputFormatPattern(short) Über diese Methode kann festgelegt werden, ob Sekunden bzw. Millisekunden immer angezeigt werden sollen oder nur, wenn sie ungleich „0“ sind.

 

3.5.16 LabelField

Die Klasse com.cisag.pgm.gui.LabelField dient primär der Darstellung von einfachen (read-only) Texten in Tabellen (siehe 3.6.3 Table). In Tabellen (und Listen) ist ein Label gegenüber einem entsprechend konfiguriertem TextField vorzuziehen, da es weniger Ressourcen benötigt. Die Klasse com.cisag.pgm.gui.Label kann in Tabellen nicht benutzt werden, da Spalten von Tabellen nur über Instanzen von com.cisag.pgm.gui.Field definiert werden können. Aus diesem Grund ist LabelField von Field abgeleitet.

Instanzen von LabelField werden über den Konstruktor LabelField(String guid, String path) erzeugt.

Mit den Methoden setText(String value) bzw. setValueFromObject(Object obj) wird das LabelField mit einem Text versehen. Der aktuelle Inhalt des Feldes kann mit getValueAsObject() abgefragt werden.

Hinweis: Anders als die Klasse com.cisag.pgm.gui.Label kann das LabelField entweder einen Text oder ein Icon darstellen, aber nicht beides gleichzeitig. Die Möglichkeit mit dem LabelField Icons anzuzeigen sollte jedoch nicht genutzt werden[13]. Stattdessen sollte das IconField (siehe 3.5.17 IconField) benutzt werden.

3.5.17 IconField

Die Klasse com.cisag.pgm.gui.IconField dient primär der Darstellung von Icons in Tabellen (siehe 3.6.3 Table). Icons werden normalerweise mit einem com.cisag.pgm.gui.Label (siehe 3.4.1 Label) angezeigt. Die Klasse Label kann in Tabellen nicht benutzt werden, da Spalten von Tabellen nur über Instanzen von com.cisag.pgm.gui.Field definiert werden können. Aus diesem Grund ist IconField von Field abgeleitet. Die Klasse com.cisag.pgm.gui.LabelField erfüllt eine ähnliche Aufgabe für Texte.

Das Feld wird mithilfe des üblichen Konstruktors für Felder IconField(String guid, String path) instanziiert.

Icons, d. h. Instanzen von com.cisag.pgm.gui.Icon können dem Feld über die Methoden setValue(Icon) oder setValueFromObject(Object) zugewiesen werden. Das Setzen des ToolTip-Textes beim Feld erfolgt mit der Methode setToolTipText(String text).

Es ist nicht möglich, das IconField mit einem Beschriftungstext (Label) zu versehen.

3.5.18 LayeredIconField

Die Klasse com.cisag.pgm.gui.LayeredIconField bietet die Möglichkeit mehrere Icons gleichzeitig anzuzeigen. Die Icons werden dabei übereinander (z-Richtung) angeordnet. Wenn nicht nur das oberste Icon sichtbar sein soll, dann müssen die Icons (zumindest teilweise) transparent sein.

Die Icons, welche das Feld visualisieren sollen, müssen diesem mithilfe der Methode addIcon(short value, Icon icon) zugefügt werden.

Die Visualisierung der Icons erfolgt mit Aufruf der Methode setValue(short[] value), wobei das Array die Indizes der Icons enthält, die gezeigt werden sollen. Ähnliches bewirkt die Methode setValueFromObject(Object obj), die als Objekt-Parameter nur ein short[] Array zuläßt.

getValue() bzw. getValueAsObject() liefert die Indizes der aktuell visualisierten Icons zurück. Mithilfe der Methode containsIcon(short value) kann abgefragt werden, ob dem Feld ein Icon unter dem angegebenen Index bekannt ist.

3.5.19 GuidField

Die Klasse com.cisag.pgm.gui.GuidField wurde speziell für die Ein- und Ausgabe von GUIDs erstellt.

Die Methoden getValue() und setValue(byte[]) liefern die GUID in Form eines Arrays (byte[]) zurück bzw. akzeptieren die GUID nur in dieser Form. Das gleiche gilt für setValueFromObject(Object value) und getValueAsObject().

Über die Methode getStringValue() erhält man eine Stringdarstellung der GUID.

3.5.20 FavoriteField

Das com.cisag.pgm.gui.FavoriteField dient in Tabellen zur Kennzeichnung einer Tabellenzeile als Standardwert bzw. „Favorit“. Alle Zellen (CheckBoxen) in der betreffenden Tabellenspalte sind miteinander synchronisiert. Es kann immer nur genau eine Zelle (von n) selektiert sein. Das Selektieren einer neuen Zelle führt immer zur Deselektion der bisherigen Zelle. Die CheckBoxen in den Zeilen verhalten sich somit wie eine Gruppe von RadioButtons.

3.5.21 PasswordField

Für die Eingabe von Kennwörtern steht die Klasse com.cisag.pgm.gui.PasswordField zur Verfügung. Das PasswordField basiert auf einem TextField, stellt jedoch auf der Benutzeroberfläche seinen Inhalt bzw. den vom Benutzer eingegebenen Text stets als „*“ Kette dar.

Über die Methoden getValue() und getValueAsObject() ist der Inhalt des Feldes als String zugänglich. Alle „white spaces“ am Anfang und/oder Ende werden automatisch entfernt (java.lang.String#trim()).

Mit setValue(String) bzw. setValueFromObject (Object) kann das Passwort serverseitig geändert werden.

3.5.22 CharacterField

Die Klasse com.cisag.pgm.gui.CharacterField dient zur Ein- und Ausgabe eines einzelnen Zeichens.

Das Feld erwartet als Wert ein Objekt des Typs java.lang.Character als Übergabeparameter in seiner setValueFromObject()-Methode.

Wird über die von der Elternklasse com.cisag.pgm.gui.Field geerbten Methode setStringValue(String) ein mehrere Zeichen langer Stringwert gesetzt, übernimmt das CharacterField den ersten Buchstaben des Strings.

3.5.23 Selektionsfelder

In einigen Anwendungsfällen, inbesondere bei Suchen und Abfrageanwendungen, ist es notwendig, eine Liste von Werten, einen Wertebereich (Intervall) und/oder ein Suchmuster (mit Platzhaltern „*“, „?“) eingeben zu können. Im Dokument Bedienungsleitfaden werden die dafür genutzen Felder als „mehrwertige Eingabefelder“ bezeichnet.

Ab Semiramis 4 stehen hierfür spezielle Feldtypen zur Verfügung. Alle neuen Selektionsfelder besitzen eine Eingabemuster-Unterstützung in Form einer Auswahlliste. Dadurch soll dem Benutzer die Möglichkeit gegeben werden, die in Semiramis üblichen Schreibweisen für Selektionen zu erlernen. Dem Benutzer werden in der Auswahlliste mehrere Vorschläge für Selektionen aufgezeigt, z. B. “beginnt mit ABC”. Wählt er eine aus, so wird das zu dem Eintrag gehörende Muster in das Feld übertragen, z. B. “ABC*”. Dieses Muster kann der Benutzer seinen Bedürfnissen anpassen und die Suche ausführen.

3.5.23.1 TextSelectionField

Das TextSelectionField dient als Selektionsfeld für alle textbasierten Datentypen.

TextSelectionField API

Die folgenden Tabellen zeigen die wichtigsten Methoden von TextSelectionField (eine vollständige Liste bzw. detaillierte Beschreibungen sind in der JavaDoc-Dokumentation von TextSelectionField zu finden):

Tabelle 70: Konstruktoren
Konstruktor Verwendung
TextSelectionField(String, String) Erzeugt ein TextSelectionField.

Als Parameter sind GUID und Pfad (logischer Datentyp) zu übergeben.

 

Tabelle 71: Datenzugriff
Methode Verwendung
getValue()

setValue(String)

Aktuellen Wert des Feldes abfragen oder ändern.

Wie bei allen Feldern stehen auch noch die von der Elternklasse Field geerbten Methoden getValueAsObject() und setValueFromObject() zur Verfügung.

getSelectionString() Liefert den aktuellen Wert so formatiert, wie er intern von den Suchen benötigt wird.

 

Tabelle 72: Anwendungsunterstützung
Methode Verwendung
getSelectionMode()

setSelectionMode(boolean)

Wird von dem TextSelectionField nicht unterstützt (immer true).

 

3.5.23.2 DecimalSelectionField

Das DecimalSelectionField dient als Selektionsfeld für folgende numerischen Datentypen:

  • cisag.pgm.datatype.CisDecimal
  • lang.Integer bzw. int
  • lang.Long bzw. long
  • lang.Short bzw. short
  • lang.Byte bzw. byte
DecimalSelectionField API

Die folgenden Tabellen zeigen die wichtigsten Methoden von DecimalSelectionField (eine vollständige Liste bzw. detaillierte Beschreibungen sind in der JavaDoc-Dokumentation von DecimalSelectionField zu finden):

Tabelle 73: Konstruktoren
Konstruktor Verwendung
DecimalSelectionField(
String, String)
Erzeugt ein DecimalSelectionField.

Als Parameter sind GUID und Pfad (logischer Datentyp) zu übergeben.

 

Tabelle 74: Datenzugriff
Methode Verwendung
getStringValue()

setStringValue(String)

Aktuellen Wert des Feldes abfragen oder ändern.

Das Feld liefert bzw. erwartet die Strings in normalisierter Darstellung (siehe com.cisag.pgm.datatype.CisDecimalSelectionUtility).

Wie bei allen Feldern stehen auch noch die von der Elternklasse Field geerbten Methoden getValueAsObject() und setValueFromObject() zur Verfügung.

getSelectionString() Liefert den aktuellen Wert so formatiert, wie er intern von den Suchen benötigt wird.

 

Tabelle 75: Anwendungsunterstützung
Methode Verwendung
getSelectionMode()

setSelectionMode(boolean)

Wird von dem DecimalSelectionField nicht unterstützt (immer true).
isGroupingUsed()

setGroupingUsed(boolean)

„Zifferngruppierung“ abfragen oder ändern. Diese Einstellung legt fest, ob die Ziffern mithilfe von Trennzeichen (z.B. „.“) gruppiert werden sollen. Welches Trennzeichen dazu verwendet wird, hängt von den jeweiligen Benutzereinstellungen ab.

 

3.5.23.3 CisDateSelectionField

Das CisDateSelectionField dient als Selektionsfeld für alle datums- bzw. zeitbasierten Datentypen:

  • cisag.pgm.datatype.CisDate
  • util.Date

Wie das CisDateField (siehe 3.5.12 CisDateField) benötigt auch das CisDateSelectionField eine explizite Initialiserung. Die Initialisierung erfolgt über den Aufruf von setValue(). Fehlt diese Initialisierung, kann das Feld bei getValue() kein CisDateSelection Objekt erzeugen und wirft deshalb eine java.lang.IllegalStateException. Aus dem selben Grund ist es auch nicht erlaubt, bei dem Feld den Wert einfach auf null zu setzen. Mithilfe der Klasse com.cisag.pgm.datatype.CisDateSelectionUtility können geeignete CisDateSelection Objekte erzeugt werden. Die Methode createUndefinedCisDateSelection(CisCalendar calendar) liefert beispielsweise ein CisDateSelection Objekt zurück, mit dem ein CisDateSelectionField Feld initialisiert bzw. wieder geleert werden kann. Welcher Kalender dabei zu benutzen ist, hängt von dem jeweiligen Anwendungsfall ab. Für den Fall, dass der Kalender dem aktuellen Anwendungskontext entsprechen soll, kann dieser über:

CisCalendar cisCalendar =
CisEnvironment.getInstance().getContext().
getCisCalendar();

ermittelt werden.

Auch bezüglich Prüfungen und Meldungen verhält sich das  CisDateSelectionField wie das CisDateField. Die Prüfung der Eingaben muss explizit durch die jeweilige Anwendung erfolgen bzw. angestoßen werden. Die Anwendung kann (und sollte) dabei auf die Hilfsklasse com.cisag.pgm.util.RepositoryValidation zurückgreifen, die hierfür entsprechende Methoden bereitstellt.

CisDateSelectionField API

Die folgenden Tabellen zeigen die wichtigsten Methoden von CisDateSelectionField (eine vollständige Liste bzw. detaillierte Beschreibungen sind in der JavaDoc-Dokumentation von CisDateSelectionField zu finden):

Tabelle 76: Konstruktoren
Konstruktor Verwendung
CisDateSelectionField(
String, String)
Erzeugt ein CisDateSelectionField.

Als Parameter sind GUID und Pfad (logischer Datentyp) zu übergeben.

 

Tabelle 77: Datenzugriff
Methode Verwendung
getValue()

setValue(CisDateSelection)

Aktuellen Wert des Feldes abfragen oder ändern.

Wie bei allen Feldern stehen auch noch die von der Elternklasse Field geerbten Methoden getValueAsObject() und setValueFromObject() zur Verfügung.

getTimeIntervals() Liefert den aktuellen Wert des Feldes als Array von CisTimeInterval Objekten zurück.
getSelectionString() Liefert den aktuellen Wert so formatiert, wie er intern von den Suchen benötigt wird.

 

 

Tabelle 78: Anwendungsunterstützung
Methode Verwendung
getSelectionMode()

setSelectionMode(boolean)

Wird von dem CisDateField nicht unterstützt (immer true).
isTimeZoneEditable()

setTimeZoneEditable(
boolean)

Legt fest, ob die Zeitzone durch den Benutzer geändert werden kann oder nicht.
setTimeOutputFormatPattern(short) Über diese Methode kann festgelegt werden, ob Sekunden bzw. Millisekunden immer angezeigt werden sollen oder nur, wenn sie ungleich „0“ sind.

 

3.5.23.4 AbstractCisQuantitySelectionField

Die Klasse AbstractCisQuantitySelectionField ist die Basisklasse für alle Varianten von „Quantity“-Selektionsfeldern aus dem Package com.cisag.app.general.gui. Hierzu zählen beispielsweise:

  • DomesticAmountSelectionField
  • DurationSelectionField
  • ForeignAmountSelectionField
  • QuantitySelectionField

3.5.24 ValidFromUntilFieldSupport

Anwendungen, die mit zeitabhängigen Business Objekten arbeiten, benötigen in der Regel auch entsprechende Felder, um den Beginn („From“) und das Ende („Until“) des Gültigzeitraums anzuzeigen bzw. durch den Benutzer bearbeiten zu lassen. Grundsätzlich kann jede Anwendung dazu zwei einzelne CisDateFields erzeugen und diese dann geeignet konfigurieren und platzieren. Um sich diese Arbeit zu erleichern und gleichzeitig für ein einheitliches Aussehen und Verhalten zu sorgen, kann die Hilfsklasse ValidFromUntilFieldSupport benutzt werden.

Diese Klasse ist nicht von Field oder VisualElement abgeleitet, sondern stellt lediglich Methoden bereit um entsprechend konfigurierte Elemente zu erzeugen.

Die Hilfsklasse kann auf zwei unterschiedliche Weisen genutzt werden:

  • Mithilfe der Methode createSingleFieldRepresentation() kann ein spezielles Feld erzeugt werden, das intern zwei CisDateFields als Subfelder verwendet. Dieses Feld kann dann einem Container hinzugefügt werden.
  • Alternativ, d.h. ohne den Aufruf von createSingleFieldRepresentation() können die Subfelder auch direkt verwendet und einzeln einem Container hinzugefügt werden.
  • Von ValidFromUntilFieldSupport erzeugter Container

3.5.24.1 ValidFromUntilFieldSupport API

Die folgenden Tabellen zeigen die wichtigsten Methoden von ValidFromUntilFieldSupport (eine vollständige Liste bzw. detaillierte Beschreibungen sind in der JavaDoc-Dokumentation von ValidFromUntilFieldSupport zu finden):

Tabelle 79: Konstruktoren
Konstruktor Verwendung
ValidFromUntilFieldSupport(String, String, String, String) Erzeugt eine Instanz von ValidFromUntilFieldSupport

Für das zu erzeugende „From“ bzw. „Until“ Feld sind jeweils eine GUID und ein Pfad zu übergeben. Die übergebenen Pfade müssen kompatibel mit den für ein CisDateField notwendigen logischen Datentypen sein (siehe 3.5.12 CisDateField).

Die Klasse verfügt auch über einen Konstruktor, bei dem nur die beiden GUIDs angegeben werden müssen. In diesem Fall greift die Implementierung auf generische logische Datentypen zurück. Die Verwendung dieses Konstruktors wird daher nicht empfohlen.

 

Tabelle 80: Datenzugriff
Methode Verwendung
getFromDate() Aktuellen „From“-Wert abfragen. Der Rückgabewert ist ein java.util.Date Objekt. Die Zeitzoneninformation ist immer identisch mit dem „Until“-Wert und kann dort abgefragt werden.

Alternativ zu dieser Methode kann auch die Methode getFromField() verwendet werden. Bei dem zurückgelieferten CisDateField kann dann beispielsweise die Methode getValue() aufgerufen werden.

getUntilDate() Aktuellen „Until“-Wert abfragen. Der Rückgabewert ist ein com.cisag.pgm.datatype.CisDate Objekt. Die darin enthaltene Zeitzoneninformation gilt ebenso für den „From“-Wert.

Alternativ zu dieser Methode kann auch die Methode getUntilField() verwendet werden. Bei dem zurückgelieferten CisDateField kann dann beispielsweise die Methode getValue() aufgerufen werden.

setValue(Date, CisDate) Gemeinsames Ändern von „From“- und „Until“-Wert. Der „From“-Wert ist als java.util.Date zu übergeben, der „Until“-Wert als com.cisag.pgm.datatype.CisDate. Die im „Until“-Wert vorhandene Zeitzoneninformation gilt für beide Werte.

 

Tabelle 81: Anwendungsunterstützung
Methode Verwendung
createSingleFieldRepresentation(String, String) Erzeugt ein („äußeres“) Feld, welches intern zwei Subfelder für „From“ und „Until“ besitzt. Die Parameter für GUID und Pfad beziehen sich auf das äußere Feld (die Parameter für die internen Felder sind bereits im Konstruktor von ValidFromUntilFieldSupport zu übergeben).

Das erzeugte Feld kann dann wie jedes andere Feld einem Container hinzugefügt werden. Für den Datenzugriff sind jedoch die Methoden von ValidFromUntilFieldSupport zu nutzen.

getFromField()

getUntilField()

Zugriff auf die intern verwendeten Felder (CisDateField).

Der direkte Zugriff auf diese Felder ist beispielsweise notwendig, um die richtigen „Message-IDs“ bei dem jeweiligen Subfeld zu registrieren.

getSingleRepresentation() Liefert das „äußere“ Feld zurück. Voraussetzung ist jedoch, dass dieses zuvor mit createSingleFieldRepresentation() erzeugt wurde.

 

3.5.25 ValidFromFieldSupport

Anwendungen, die mit zeitabhängigen (versionierten) Business Objekten arbeiten, benötigen in der Regel auch entsprechende Elemente um eine bestimmte Version durch den Benutzer auswählen zu lassen. Grundsätzlich kann jede Anwendung, die dazu notwendigen Elemente selbst erzeugen, geeignet konfigurieren und platzieren. Um sich diese Arbeit zu erleichern und gleichzeitig für ein einheitliches Aussehen und Verhalten zu sorgen, sollte jedoch die Hilfsklasse ValidFromFieldSupport benutzt werden.

Wie die Hilfsklasse ValidFromUntilFieldSupport ist diese Klasse nicht von Field oder VisualElement abgeleitet, sondern stellt lediglich Methoden bereit, um entsprechend konfigurierte Elemente zu erzeugen.

Mithilfe der Methode createField() kann ein spezielles Feld erzeugt werden, das intern aus folgenden Elementen besteht:

  • Ein CisDateField, welches das „gültig-ab“ Datum der jeweiligen Version angezeigt. Das „gültig-bis“ Datum wird als ToolTip angezeigt.
  • Zwei Schaltflächen, über die der Benutzer zwischen den Versionen (vorherige bzw. nächste Version) „blättern“ kann.
  • ValidFromField

Die Hilfsklasse stellt jedoch nur das UI bereit, das Laden oder Anlegen von Versionen muss durch die Anwendung implementiert werden.

Der Konstruktor ValidFromFieldSupport(String guid, String path, ActionListener) erlaubt die Registrierung eines ActionListeners. Dieser ActionListener wird benachrichtigt, wenn der Benutzer eine der Schaltflächen aktiviert. Über die ID der in der performAction()-Methode übergebenen Action kann der Listener die vom Benutzer gewählte Schaltfläche erkennen. Für diese IDs sind die Konstanten ValidFromFieldSupport.NEXT_VERSION bzw. ValidFromFieldSupport.PREV_VERSION definiert.

Über die Methode setValue(com.cisag.pgm.datatype. CisObject) kann der Hilfsklasse eine Instanz eines zeitabhängigen Business Objektes zugewiesen werden. Der „gültig-ab“ Zeitpunkt (CisObject#getValidFrom()) dieses Business Objektes wird dann in das Datumsfeld übernommen und der „gültig-bis“ Zeitpunkt (CisObject#getValidUntil()) wird als ToolTip übernommen. Die beiden Schaltflächen des erzeugten Feldes werden abhängig von den Werten von „gültig-ab“ bzw. „gültig-bis“ auf „enabled“ bzw. „disabled“ gesetzt.

3.6 Listen und Tabellen

Für Listen und Tabellen stehen die Klassen

  • cisag.pgm.gui.List bzw.
  • cisag.pgm.gui.Table

zur Verfügung (siehe 2.3.1 Listen und Tabellen). Zwischen den beiden Klassen gibt es zwar grundlegende Unterschiede bezüglich der Definition von Spalten bzw. dem Aufbau von Zeilen, aber es gibt auch eine Reihe von Gemeinsamkeiten. Hierzu zählen z. B.:

  • Die Strukturierung in Kopfbereich (Header), Datenbereich (Body) und Fußbereich[14] (Footer).
  • Der Aufbau des Kopfbereiches.
  • Die Verwendung eines Seitenmodells (PageModel).
  • Die Repräsentation von Datensätzen durch Instanzen von cisag.pgm.base.obj.CisListPartMutable.
  • Die Selektion von Datensätzen.
  • Den Datenexport als CSV-Datei

Diese gemeinsamen Eigenschaften (siehe 3.6.1 Gemeinsame Eigenschaften) sind in der Klasse List implementiert. Die Klasse Table erweitert List um spezielle Eigenschaften für Tabellen (siehe 3.6.3 Table). Es gibt allerdings auch ein paar Eigenschaften, die an der Klasse List definiert sind, aber bei Tabellen nicht zur Verfügung stehen (siehe 3.6.2 List).

3.6.1 Gemeinsame Eigenschaften

Listen und Tabellen bestehen aus bis zu drei Bereichen:

  • Kopfbereich (Header)
  • Datenbereich (Body)
  • Fußbereich[15] (Footer)
  • Bereiche in Listen
  • Bereiche in Tabellen

3.6.1.1 Kopfbereich

Im Kopfbereich von Listen und Tabellen befindet sich oben eine Symbolleiste (com.cisag.pgm.gui.Coolbar) und darunter die Spaltenüberschriften zu den angezeigten Daten. Die Symbolleiste verfügt über eine Reihe von Standardelementen und kann zudem durch eigene Elemente erweitert werden.

Über die Methode setHeaderVisible(boolean) kann die Sichtbarkeit des gesamten Headers gesteuert werden.

Mithilfe der Methoden addHeaderElement() bzw. addHeaderToggle() können der Symbolleiste weitere Elemente hinzugefügt werden.

Mit setHeaderExpandable(boolean value) kann die Symbolleiste veranlasst werden, bei Platzmangel einzelne Elemente in ein Popup-Fenster auszulagern. Eine genauere Erläuterung dieses Mechanismus ist in Kapitel 3.7.1 CoolBar zu finden.

Die Methode addActionListener(ActionListener) erlaubt die zentrale Registrierung eines ActionListeners bei allen Elementen, die zu der Symbolleiste gehören.

PageButton

Zu der Standard-Symbolleiste von Listen und Tabellen gehört der „PageButton“ (siehe 3.6.4 PageButton).

Die Sichtbarkeit des PageButtons kann über die Methode setPageButtonVisible(boolean value) gesteuert werden.

Über die Methode setPageButtonListener(Action-Listener) ist es möglich, selbst auf die erzeugten Ereignisse (Actions) von dem PageButton zu reagieren. In diesem Fall muss der registrierte ActionListener, das Vorwärts- bzw. Rückwärtsblättern, d. h. die Steuerung des Daten- und Seitenmodells übernehmen.

3.6.1.2 Datenbereich

Im Datenbereich (Body) werden die Datensätze des Datenmodells seitenweise angezeigt (siehe 3.6.1.3 Seitenmodell).

Datenmodell

Das Datenmodell von Listen und Tabellen basiert, wie bereits in Kapitel 2.3.1 Listen und Tabellen beschrieben, auf einer Liste von Datensätzen, wobei jeder Datensatz durch eine Instanz von com.cisag.pgm.base.obj.CisList PartMutable repräsentiert wird. Dieses Objekt dient dabei als „generischer Datencontainer“. Die Eigenschaft „data“ des Objekts kann dazu genutzt werden, eine Referenz auf ein beliebiges Objekt zu speichern. Die übrigen Eigenschaften von CisListPartMutable dienen überwiegend zur Speicherung von Informationen über den Zustand des Datensatzes (z. B. „geändert“, „als gelöscht markiert“, „selektiert“, usw.).

Typischerweise enthält das Datenmodell nur einen Teil der tatsächlich vorhandenen Datensätze, insbesondere um den Hauptspeicherbedarf und die Antwortzeit (Ladezeit) unter Kontrolle zu behalten[16]. So werden z. B. bei Suchergebnissen zunächst immer nur die ersten „n“ gefundenen Datensätze in das Modell übernommen und angezeigt. Durch „Blättern“ kann der Benutzer das Nachladen von weiteren Datensätzen anstoßen (siehe 3.6.4 PageButton). Zusätzlich kann über die Methode setMaximumVirtualRows() eine obere Schranke für die ladbaren Datensätze definiert werden.

Das Hinzufügen von Datensätzen erfolgt mit den Methoden addRow(CisListPartMutable data) bzw. insertRow(int aheadOf, CisListPartMutable data), das Ändern (Austauschen) eines Datensatzes mit setRow(CisListPart Mutable data) und das Löschen mit removeRow(int rowIdx). Zum Löschen aller Datensätze steht die Methode clear() zur Verfügung.

Über die Methode setAllRowsLoaded(boolean value) kann der Liste/Tabelle mitgeteilt werden, ob das Datenmodell vollständig ist, d. h. dass sich alle vorhandenen Datensätze in dem Modell befinden bzw. dass es keine weiteren Datensätze mehr gibt. Diese Information wird an den „PageButton“ weitergegeben, der wiederum den Benutzer informiert[17].

Hinweis:
Bei Listen und Tabellen muss die Aktualisierung des Clients explizit über die Methode display() angestoßen werden. Die generelle Regel dazu lautet: Immer wenn auf eine Liste oder Tabelle zugegriffen wurde, dann muss zum Abschluss noch display() aufgerufen werden, damit das Modell konsistent ist und alle Änderungen auf dem Client sichtbar werden.

Selektion

Listen und Tabellen erlauben das „Markieren“ von Datensätzen durch den Benutzer. Über die Methode setSelectionMode() kann festgelegt werden, ob nur ein Datensatz oder auch mehrere Datensätze gleichzeitig markiert werden können. Die aktuelle Selektion kann mit den Methoden getSelectedRow(), getSelectedRowList() bzw. getSelectedRows() abgefragt oder über die Methoden setRowSelected(int rowIdx) bzw. clearSelections() geändert werden. In der Standardeinstellung kann die Selektion nur Datensätze aus der aktuellen Seite beinhalten, d.h. bei jedem Seitenwechsel geht die vorherige Selektion verloren. Über die Methode setPageSelectionEnabled() kann diese Standardeinstellung geändert werden.

Hinweis:
In Listen wird für die Mehrfachselektion häufig ein anderer Weg beschritten und in jeder Zeile eine zusätzliche CheckBox platziert.

Neben der Markierung von Zeilen wird auch eine „Open-Action“ unterstützt. Die mit setOpenAction(Action a) registrierte Action wird ausgelöst, wenn der Benutzer eine Zeile entweder mit ENTER oder, je nach Benutzereinstellung, mit Einfach- oder Doppelklick „öffnet“.

Layout

Über die Methoden setVisibleRowCount() und setPreferredHeightPolicy() kann gesteuert werden, wieviel Platz die Liste/Tabelle in dem übergeordneten Container beanspruchen soll.

3.6.1.3 Seitenmodell

Die Anzeige der Datensätze erfolgt seitenweise, d. h. von den „n“ (geladenen)-Datensätzen werden nur jeweils „m“ auf dem Client angezeigt.

Durch „Blättern“ (siehe 3.6.4 PageButton) werden dann die nächsten[18] bzw. die vorherigen „m“-Datensätze angezeigt. Der Wert „m“ wird als „Page-Size“ bezeichnet und lässt sich im Konstruktor von Listen und Tabellen oder durch die Methode setPageSize(int value) festlegen. Idealerweise wird der Wert so gewählt, dass die Listen bzw. Tabellen ihre Anzeigefläche voll ausnutzen, aber gerade noch keinen Scrollbalken verwenden. Es wird empfohlen, wenn möglich[19], das vertikale Scrollen mithilfe der Methode setVerticalScrollBarPolicy(VERTICAL_SCROLLBAR_NEVER) ganz abzuschalten. In diesem Fall wird die optimale „Page-Size“ von der Liste/Tabelle automatisch berechnet und aktualisiert. Der Wert im Konstruktor ist damit mehr oder weniger bedeutungslos, sollte aber mindestens 1 sein.

Zusätzlich verfügen Listen und Tabellen über die folgenden Methoden:

  • int getCurrentVisibleRowCount();
  • setCurrentVisibleRowCountChangeAction(Action a)

Die erste Methode liefert die aktuelle Anzahl der sichtbaren Zeilen, die dann mit setPageSize() gesetzt werden kann. Die zweite Methode erlaubt die Registrierung einer Action, die immer dann ausgelöst wird, wenn sich der Wert von „currentVisibleRowCount“ geändert hat. Mithilfe dieser beiden Methoden kann die automatische Anpassung der „Page-Size“ auch selbst programmiert werden. Es gilt aber auch hier die Einschränkung, dass die Höhe aller Zeilen konstant sein muss.

3.6.1.4 Datenexport

Sowohl Liste als auch Tabelle verfügen über eine generische Implementierung für den Datenexport. Es werden alle bereits geladenen Datensätze als „CSV-Datei“ exportiert[20].

Der Datenexport basiert direkt auf den für eine Zeile verwendeten VisualElements. Über den Wert, den es bei  getDataColumnSupport() zurückliefert, bestimmt jedes VisualElement, wie es zu exportieren ist:

  • Liefert es null, dann wird es ignoriert. Es sei denn es handelt sich um einen Container, dann wird dieser rekursiv abgesucht.
  • Über die „Column-ID“ wird ein VisualElement einer Spalte zugeordnet.
  • Ein VisualElement kann seine Daten in mehrere Subspalten aufteilen.
  • Von jeder Subspalte können Wert und Überschrift abgefragt werden.

Alle von com.cisag.pgm.gui.Field abgeleiteten Klassen verfügen über eine entsprechende Standardimplementierung. Diese liefert die GUID des Feldes als „Column-ID“ zurück. Die anderen Eigenschaften sind abhängig von dem jeweiligen Feldtyp. Die Überschrift (auch für die Subspalten) basiert dabei immer auf dem „Label“ aus der Datadescription.

Bei der Erzeugung von Listen bzw. Tabellen muss also darauf geachtet werden, dass alle verwendeten Felder über eine eindeutige[21] GUID und eine sinnvolle DataDescription verfügen. Ist dies nicht der Fall, so werden diese Felder beim Datenexport möglicherweise nicht oder falsch behandelt.

3.6.2 List

Die Verwendung von Listen erfordert folgende Schritte:

  • Erzeugung einer Instanz von
  • Implementieren eines „ListViewCreators“ (siehe 6.2.2 ListViewCreator).
  • Implementieren eines (oder mehrerer) „ListViews“ (siehe 6.2.3 ListView).
  • Bereitstellen eines (oder mehrerer) Views für die Spaltenüberschriften.
  • Festlegen von gemeinsamen Spalten für die ListViews.
  • (Optional) Bereitstellen eines Views für die Fußzeile.
  • (Optional) Verwenden der „MetaCheckBox“ für die Mehrfachselektion.
Erzeugung von Listen

Die Erzeugung einer Liste erfolgt über den Konstruktor List(String guid, int size, boolean editable, ListViewCreator creator). Der Parameter „guid“ ordnet der Liste (VisualElement) eine GUID zu. Über den Parameter „size“ wird die (initiale[22]) Seitengröße der Liste festgelegt. Der Parameter „editable“ legt fest, ob es sich bei der Liste insgesamt um eine editierbare Liste oder um eine so genannte „Ausgabeliste“ handeln soll. Über den Parameter „creator“ ist der Liste eine Factory für die Erzeugung von „ListViews“ zu übergeben. Bei Bedarf kann der ListViewCreator auch später über die Methode setListViewCreator(List ViewCreator) gesetzt werden.

Spaltenüberschriften

Da die Visualisierung der Datensätze durch die ListViews erfolgt, kann die Liste die zugehörigen Spaltenüberschriften nicht selbst anbieten. Sie stellt jedoch den Platz und entsprechende Methoden bereit, um eigene Views als Spaltenüberschrift in den Kopfbereich einfügen zu können. Dabei sollte die Struktur der verwendeten ListViews durch eine oder mehrere Zeilen (Views) nachgebildet werden. Zum Hinzufügen dieser Views stehen die Methoden addTitleBar(View view) bzw. addTitleBar(View view, int styleLevel) zur Verfügung. Der Parameter „styleLevel“ kann genutzt werden, um die Überschriften mit speziellen Schriftattributen auszustatten.

Hinweis:
Die als Überschrift verwendeten Views, sollten (wie die ListViews) ihre Elemente an den Führungslinien der Liste ausrichten), d. h. es sollte ein StandardLayout (leerer Konstruktor!) als Layout-Manager verwendet werden.

Wenn der Liste mit addTitleBar(View view) eine oder mehrere Überschriften hinzugefügt wurden, erscheint automatisch ein zusätzliches Steuerelement in der Symbolleiste der Liste. Über diesen „ToggleButton“ lassen sich die Spaltenüberschriften durch den Benutzer aus- und einblenden.

Spaltenbreiten

Damit die Inhalte der Zeilen (ListViews), der Überschriften und der Fußzeile an gemeinsamen Führungslinien ausgerichtet werden, sollten die Führungslinien bzw. Spalten (siehe 3.9.1 StandardLayout) nur an der Liste definiert werden. Hierzu bietet die Liste die Methoden setColumnWidths(double[] widths) und setColumnWidths(double[] widths, double[] leftMargins, double[] rightMargins) an. Die Spezifikation der Breiten bzw. Abstände erfolgt analog zu den vergleichbaren setGuides() Methoden von VisualElementContainer, nur dass hier die Breite des Labels immer als „0“ festgelegt ist.

Hinweis:
Damit die definierten Führungslinien an der Liste tatsächlich für die Ausrichtung der Spaltenüberschriften, ListViews und Fußzeile genutzt werden, dürfen dort keine eigenen Führungslinien (Spalten) definiert werden.

Fußbereich

Ähnlich wie für die Spaltenüberschriften, stellt die Liste auch Platz und Methoden für die Verwendung von Fuß- bzw. Summenzeilen bereit. Dabei kann auch hier die Struktur der verwendeten ListViews durch eine oder mehrere Zeilen (Views) nachgebildet werden. Zum Hinzufügen dieser Views steht die Methode addTotalBar(View view) zur Verfügung.

Die Fußzeilen werden immer am unteren Rand der Liste (nicht als letzter Datensatz) angezeigt.

MetaCheckBox

Die „MetaCheckBox“ ist für die Anwendungsfälle vorgesehen, in denen die Auswahl von Datensätzen über CheckBoxen (im ListView) erfolgt und die Funktion „Alle auswählen“ über eine (zusätzliche) CheckBox in der Symbolleiste der Liste möglich sein soll.

Die „MetaCheckBox“ für die Symbolleiste lässt sich mit der Methode createMetaCheckBox(int column, String view) erzeugen[23]. Der Parameter „column“ spezifiziert die Position (Spalte) in den ListViews, der Parameter „view“ hat keine Funktion und sollte „null“ sein.

Die CheckBoxen für die einzelnen ListViews müssen über die Methode createDependentCheckBox(String view) erzeugt und dem jeweiligen ListView manuell hinzugefügt werden. Der Parameter „view“ muss mit dem Namen des ListViews übereinstimmen.

3.6.2.1 ListStyle

Die Klasse com.cisag.pgm.gui.ListStyle legt verschiedene Visualisierungseigenschaften für Listen bzw. ListViews fest. Zu diesen Eigenschaften zählen z. B.:

  • Hintergrundfarbe
  • Schriftfarbe
  • Schriftart, Schriftstil und -größe
  • Rahmenart
  • Darstellung von selektierten Einträgen

Folgende Werte sind zur Zeit definiert:

ListStyle Verwendung
DIALOG „Dialoglisten“
OUTPUT „Ausgabelisten“
SEARCH Ergebnislisten von Suchen
XOUTPUT Erweiterte „Ausgabelisten“ (ExtendedListView)
XINPUT Erweiterte „Dialoglisten“ (ExtendedListView)
XINPUT2 Erweiterte „Dialoglisten“ (ExtendedListView) — zweite Ebene
XINPUT3 Erweiterte „Dialoglisten“ (ExtendedListView) — dritte Ebene

 

Sowohl die Liste (com.cisag.pgm.gui.List) als auch die einzelnen ListViews (com.cisag.pgm.gui.ListView) verfügen über eine Eigenschaft „style“. Bei der Liste wird diese Eigenschaft automatisch vorbelegt und zwar mit ListStyle.DIALOG bei editierbaren Listen bzw. mit ListStyle.OUTPUT bei nicht editierbaren Listen[24]. Mit setStyle() kann der Liste auch ein anderer ListStyle zugewiesen werden[25]. Bei den ListViews kann die Eigenschaft „style“ entweder im Konstruktor oder über die Methode setStyle() gesetzt werden. Ohne eine solche explizite Angabe wird der definierte Wert bei der Liste benutzt.

3.6.2.2 ListViewCreator

Die von der Liste benutzten ListView-Objekte werden nicht von der Liste selbst erzeugt, sondern müssen von der Anwendung bereitgestellt werden. Dazu muss die Anwendung eine entsprechende Factory implementieren und der Liste (z. B. über den Konstruktor) bereitstellen.

Das Interface com.cisag.pgm.gui.ListViewCreator spezifiziert das API, das durch diese Factory implementiert werden muss:

public ListView createView(String viewName);

Die Liste ruft diese Methode immer dann auf, wenn sie für die Visualisierung eines Datensatzes (repräsentiert durch eine Instanz von com.cisag.pgm.base.obj.CisList-PartMutable) eine passende Instanz von com.cisag.pgm. gui.ListView benötigt. Beim Aufruf der Methode, übergibt die Liste die Eigenschaft „viewName“ aus dem zugehörigen Datensatz (CisListPartMutable) an die Factory. Bei Bedarf, kann die Factory anhand dieses Parameters entscheiden wie die Instanz von ListView zu erzeugen bzw. zu konfigurieren ist. Das setzt voraus, dass die mit addRow() bzw. insertRow() hinzugefügten Datensätze über entsprechend konfigurierte „View-Namen“ verfügen.

Die Liste fordert Instanzen von ListView nur für die in der aktuell angezeigten Seite an, nicht für alle geladenen Datensätze des Modells. Soweit wie möglich, werden die einmal angeforderten Instanzen auch für Folgeseiten benutzt (recycled), also nicht neu angefordert. Die Wiederbenutzung ist allerdings nur bei gleichem „View-Namen“ möglich.

3.6.2.3 ListView

Die abstrakte Klasse com.cisag.pgm.gui.ListView dient der Visualisierung von Datensätzen aus der Liste.

Die Liste delegiert die Visualisierung von Datensätzen, an so genannte ListViews. Aufgabe dieser ListViews ist es, die entsprechenden UI-Elemente zu erzeugen und die Daten zwischen Datensatz und UI-Elementen auszutauschen. Dabei sind die ListViews nicht an eine bestimmte Instanz von Datensatz gebunden, sondern nur an einen bestimmten Typ. Eine Instanz einer ListView-Implementierung ist in der Lage (nacheinander) verschiedene Datensätze gleichen Typs zu visualisieren.

Die abstrakte Interface com.cisag.pgm.gui.ListView spezifiziert das API, das durch einen „ListView“ implementiert werden muss:

abstract void dataToUi(CisListPartMutable row);

void dataFromUi(CisListPartMutable row);

Das Überschreiben der zweiten (leeren) Methode ist nicht notwendig, wenn es sich bei der Liste um eine reine Ausgabeliste handelt, also kein „Rückwärts-Mapping“ der Benutzereingaben auf die Datensätze erforderlich ist.

dataToUi()

Die Liste ruft die Methode dataToUi immer dann auf, wenn der zugehörige Datensatz in einer Zeile der aktuellen Seite angezeigt bzw. aktualisiert werden soll. Bei mehreren Datensätzen erfolgt ein separater Aufruf für jede Zeile.

Aufgabe der Implementierung ist es, die Daten aus der übergebenen Instanz von CisListPartMutable auf die UI-Elemente des ListViews zu verteilen. Welche Daten das sind, hängt von der jeweiligen Anwendung ab. Häufig wird die Eigenschaft „data“ des CisListPartMutable dazu benutzt, um eine Referenz auf eine Instanz eines Business Objektes zu speichern. In diesem Fall würden z. B. die Attributwerte des Business Objektes auf die UI-Elemente zu verteilen sein.

Die UI-Elemente des ListViews werden normalerweise bei seiner Erzeugung, d. h. entweder im Konstuktor oder durch die Factory (ListViewCreator) erzeugt und dem ListView (Container) hinzugefügt.

dataFromUi()

Die Liste ruft die Methode dataFromUi immer dann auf, wenn die Benutzereingaben einer Zeile in den zugehörigen Datensatz zu übernehmen sind. Bei mehreren Datensätzen erfolgt ein separater Aufruf für jede Zeile.

Aufgabe der Implementierung ist es, die aktuellen Daten der UI-Elemente abzufragen und in der übergebenen Instanz von CisListPartMutable zu speichern. Es handelt sich hierbei um die „Umkehrfunktion“ von dataToUi.

ListStyle

Die Gestaltung (Farben, Rahmen etc.) erfolgt anhand des zugewiesenden ListStyles (siehe 3.6.2.1 ListStyle). Jeder Instanz von ListViews kann ein eigner „ListStyle“ zugewiesen werden. Üblicherweise wird der ListStyle der Liste übernommen.

3.6.2.4 ExtendedListView

Die Klasse com.cisag.pgm.gui.ExtendedListView erweitert ListViews um eine Zeilenüberschrift (row header), wie sie z. B. in den Dialog-Listen (siehe Semiramis-Styleguide) oder in den Cockpits benötigt wird. Es werden jedoch nur der Platz, das Layout und die entsprechende Zugriffsmethoden für die Zeilenüberschrift (Header) und den Datenbereich bereitgestellt. Der konkrete Inhalt ist durch die Subklassen bereitzustellen.

Wenn in der Zeilenüberschrift der Status des Datensatzes (CisListPartMutable) angezeigt werden soll, so kann als Implementierungshilfe die Klasse RowHeader benutzt und mit addHeaderPaneElement() dem Header hinzugefügt werden.

3.6.2.5 RowHeader

Die Klasse com.cisag.pgm.gui.RowHeader wird benutzt, um in der Zeilenüberschrift (row header) von Listen und Tabellen den Status des angezeigten Datensatzes zu visualisieren. Bei Tabellen geschieht es automatisch[26], bei Listen müssen die ListViews bzw. die ExtendedListViews entsprechend implementiert werden.

Die Klasse RowHeader erweitert die Klasse com.cisag.pgm. gui.Label um die Methode setRowStatus(com.cisag. pgm.base.obj.CisListPartMutable row). Der Aufruf dieser Methode führt dazu, dass abhängig von dem Status des übergebenen Datensatzes, das Label mit einem passenden Symbol (Icon) versehen wird. Ausgewertet werden dabei die Eigenschaften:

  • „deleted“
  • „selected“
  • „persistent“
  • „changed“

Typischerweise wird die Klasse RowHeader in Subklassen von ExtendedListView (siehe 3.6.2.4 ExtendedListView) verwendet. Das RowHeader-Objekt wird mit addHeaderPaneElement()dem Header-Bereich des ExtendedListViews hinzugefügt und in der dataToUi()-Methode wird dann die Methode setRowStatus() aufgerufen, um den Status des Datensatzes durch das RowHeader-Objekt visualisieren zu lassen.

3.6.3 Table

Die Klasse com.cisag.pgm.gui.Table ist von der Klasse com.cisag.pgm.gui.List abgeleitet und erbt von dieser Klasse insbesondere das seitenorientierte Datenmodell.

Die Verwendung von Tabellen erfordert folgende Schritte:

  • Erzeugung einer Instanz von
  • Definieren der Tabellenspalten.
  • Implementieren eines „TableDataManagers“ (siehe 6.3.1 TableDataManager).
Erzeugung von Tabellen

Die Erzeugung einer Tabelle erfolgt über den Konstruktor Table(String guid, int size, boolean editable, TableDataManager manager)[27]. Der Parameter „guid“ ordnet der Tabelle (VisualElement) eine GUID zu. Über den Parameter „size“ wird die (initiale[28]) Seitengröße der Tabelle festgelegt. Der Parameter „editable“ legt fest, ob es sich bei der Tabelle insgesamt um eine editierbare Tabelle oder um eine Ausgabetabelle handeln soll[29]. Über den Parameter „manager“ ist der Tabelle ein so genannter TableDataManager zu übergeben. Bei Bedarf kann der TableDataManager auch später über die Methode setTableDataManager(TableDataManager) gesetzt werden.

Definieren von Tabellenspalten

Während bei der Liste die Visualisierung und das Mapping zwischen Datensätzen und UI-Elementen komplett an ListViews delegiert wird, wurde bei der Tabelle ein anderes Verfahren gewählt. Bei der Tabelle wird dem Umstand Rechnung getragen, dass für alle Datensätze die Anzahl und der Typ der Spalten indentisch sind. Somit braucht die Definition der UI-Elemente nicht für jede Zeile neu zu erfolgen, sondern nur einmal für die ganze Tabelle.

Für jede gewünschte Spalte ist ein entsprechendes Feld zu instanziieren, zu konfigurieren und der Tabelle über die Methode addColumn(int idx, Field field) hinzuzufügen.

Diese Felder erfüllen folgende Aufgaben:

  • Aus den Metadaten des Feldes werden die Spaltenüberschrift, ToolTip, Direkthilfe usw. abgeleitet.
  • Sie dienen als Prototyp bzw. Factory[30] für die, in den konkreten Tabellenzellen verwendeten Felder (Zelleditoren).
  • Das Mapping zwischen Datensatz und Tabellenzellen wird über diese Felder gemacht (siehe 6.3.1 TableDataManager).

Im Bereich der Zeilenüberschrift (row header) kann mit addRowNumber(Field field) auf ähnliche Weise eine zusätzliche Spalte, z. B. für die Zeilennummerierung (Positionsnummern), hinzugefügt werden[31]. Mit setRowHeaderVisible(boolean) können die Zeilenbeschriftungen als Ganzes zu- bzw. abgeschaltet werden.

Die Sichtbarkeit von Spalten kann über setColumnVisible (int idx, boolean visible) bzw. isColumnVisible(int idx) gesteuert werden.

Horizontales Scrolling

In der Standardeinstellung passt die Tabelle die Spaltenbreiten automatisch an die verfügbare Gesamtbreite an. Bei Tabellen mit einer großen Anzahl von Spalten ist diese Vorgehensweise nicht immer wünschenswert. Über die Methode setHorizontalScrollBarPolicy() kann die Tabelle daher auch so konfiguriert werden, dass sie spaltenweise scrollt. Für diesen Fall besteht auch die Möglichkeit über die Methoden fixColumn() bzw. fixColumns() bestimmte Spalten am linken Rand zu fixieren, sodass diese Spalten immer sichtbar bleiben.

3.6.3.1 TableDataManager

Die Datensätze in einer Tabelle werden durch Instanzen von com.cisag.pgm.base.obj.CisListPartMutable repräsentiert, die Spalten der Tabellen durch Instanzen von com.cisag.pgm.gui.Field. Die Abbildung (bzw. das „Mapping“) eines Datensatzes auf die entsprechenden Felder delegiert die Tabelle an einen so genannten „TableDataManager“. Dieser muss von der Anwendung implementiert und der Tabelle (z. B. über den Konstruktor) bereitgestellt werden.

Das Interface com.cisag.pgm.gui.TableDataManager spezifiziert das API, dass durch den TableDataManager implementiert werden muss:

void dataToTable(CisListPartMutable row);

void dataFromTable(CisListPartMutable row);

Die Implementierung der zweiten Methode kann „leer“ sein, wenn es sich bei der Tabelle um eine reine Ausgabetabelle handelt, also kein „Rückwärts-Mapping“ der Benutzereingaben auf die Datensätze erforderlich ist.

dataToTable()

Die Tabelle ruft die Methode dataToTable immer dann auf, wenn der zugehörige Datensatz in einer Zeile der aktuellen Seite angezeigt bzw. aktualisiert werden soll. Bei mehreren Datensätzen erfolgt für jede Zeile ein separater Aufruf.

Aufgabe der Implementierung ist es, die Daten aus der übergebenen Instanz von CisListPartMutable auf die definierten Spalten zu verteilen. Welche Daten das sind, hängt von der jeweiligen Anwendung ab. Häufig wird die Eigenschaft „data“ des CisListPartMutable dazu benutzt, um eine Referenz auf eine Instanz eines Business Objektes zu speichern. In diesem Fall würden dann z. B. die Attributwerte des Business Objektes auf die definierten Spalten zu verteilen sein.

Bei den „definierten Spalten“ handelt es sich um die, per addColumn(int idx, Field field), der Tabelle zugefügten Felder. Die Wertübergabe erfolgt dabei über die Methoden des entsprechenden Feldes (z. B.: setValue()). Neben dem eigentlichen Wert kann auch der übrige Feldzustand angepasst werden („enabled“, „editable“, …). Voraussetzung ist natürlich, dass die Implementierung des TableDataManagers Zugriff auf die per addColumn() registrierten Instanzen von Field hat. Aus diesem Grund ist es in den Semiramis-Anwendungen üblich, das Interface TableDataManager in der Anwendungsklasse selbst zu implementieren und die Felder als Instanzvariablen zu definieren.

Nach dem Aufruf von dataToTable übernimmt die Tabelle die Werte aus den Feldern in die „echten“ Tabellenzellen. Dieser Vorgang wiederholt sich Zeile für Zeile, d. h. die Werte in den Feldern sind immer nur für die aktuelle Zeile gültig.

dataFromTable()

Die Tabelle ruft die Methode dataFromTable immer dann auf, wenn die Zellwerte (Benutzereingaben) einer Zeile in den zugehörigen Datensatz zu übernehmen sind. Bei mehreren Datensätzen erfolgt für jede Zeile ein separater Aufruf.

Aufgabe der Implementierung ist es, die aktuellen Feldwerte („definierte Spalten“) abzufragen und in der übergebenen Instanz von CisListPartMutable zu speichern. Es handelt sich hierbei also um die „Umkehrfunktion“ von dataToTable.

Die Tabelle sorgt automatisch dafür, dass zum Zeitpunkt des Aufrufs, die aktuellen Zellwerte der betroffenen Zeile in den Field-Instanzen stehen.

3.6.4 PageButton

Der so genannte „Page-Button“ zeigt dem Benutzer folgende Informationen an:

  • Nummer der aktuelle Seite.
  • Gesamtanzahl der (geladenen) Seiten.
  • Anzahl der geladenen Datensätze (als ToolTip).
  • Hinweis auf weitere (noch nicht geladene) Seiten/Datensätze („+“).

Über zwei Schaltflächen erlaubt der PageButton dem Benutzer das Blättern zwischen den Seiten („nächste“ bzw. „vorherige“ Seite). Durch die Eingabe einer Seitennummer kann der Benutzer direkt zu einer Seite „springen“.

Der PageButton wird automatisch von der Liste (vgl. Kapitel 3.6.2 List) bzw. Tabelle (vgl. Kapitel 3.6.3 Table) erzeugt und in den Header eingefügt[32].

Über die Methode getPageButton() stellt die Liste (Tabelle) den PageButton dem Anwendungsprogramm zur Verfügung. Das ist z. B. dann notwendig, wenn mit der Methode setLoader() ein ActionListener registriert wird, um in dessen performAction()-Methode weitere Datensätze nachladen zu können.

Über die Methode setPage(int) kann eine bestimmte Seite angezeigt werden. Die Methode getPage() liefert die Nummer der aktuellen Seite und getCount() die Zahl der insgesamt vorhandenen Zeilen.

3.7 Spezielle Container

3.7.1 CoolBar

Die Klasse com.cisag.pgm.gui.CoolBar dient der Darstellung von Symbolleisten, wie sie z. B. in dem Anwendungsfenster oder bei Listen und Tabellen Anwendung finden.

Der CoolBar wird im Konstruktor eine int-Konstante übergeben, die den Typ der Buttons definiert, die in der Symbolleiste enthalten sein sollen. Dieser Typ (siehe 3.4.2 Button) wird benutzt, wenn durch die CoolBar (aus einer Action) neue Buttons erzeugt werden. Der Default (leerer Konstruktor) für diesen Parameter ist Button.HEADER_BUTTON.

Des Weiteren erlaubt der Konstruktor die Registrierung eines ActionListeners, der benachrichtigt wird, wenn eines der Subelemente, also z. B. ein Button, seine Action auslöst.

Der CoolBar wird mithilfe der Methoden add(Action action), add(Action action, int side) bzw. addToggle(Action action, int side) mit Buttons bzw. ToggleButtons gefüllt, wobei aus dem übergebenen Action-Objekt ein automatisch entsprechender Button erzeugt wird. Ohne Angabe der Seite („side“) werden die Buttons der Reihe nach von links nach rechts eingefügt, wobei der zuletzt eingefügte rechts an die Reihe angehängt wird. Wenn als Parameter CoolBar.RIGHT übergeben wird, dann erfolgt die Platzierung umgekehrt von rechts nach links. Der Parameter Coolbar.RIGHT_TO_LEFT fügt das Element rechts außen an.

Zum Zweck einer optischen Unterteilung kann der Entwickler mit addSeparator(int side) eine Trennline (Separator) einfügen.

Es stehen remove()-Methoden zur Verfügung, um einen Button aus der Symbolleiste zu entfernen, wobei auch hier der Button über sein Action-Objekt spezifiziert werden muss.

Die Klasse CoolBar verfügt über die Eigenschaft expandable, die mit der Methode setExpandable(boolean value) änderbar ist und mit isExpandable() abgefragt werden kann. Im Defaultzustand steht dieser auf false. „Expandable“ bedeutet, dass Schaltflächen, die aus Platzgründen in der Symbolleiste nicht mehr dargestellt werden können, in ein Popup-Fenster ausgegliedert werden. Zum Öffnen dieses Fensters wird in die Symbolleiste am äußersten rechten Ende ein Button mit  Symbol eingefügt. Der CoolBar sorgt selbst für den Auf- bzw. Abbau des Popup-Fensters sowie des  Buttons und passt den Inhalt des Popups auch automatisch an, z. B. wenn sich die Größe des Anwendungsfensters bzw. die Länge der Symbolleiste geändert hat.

3.7.2 ButtonBar

Die Klasse ButtonBar wird hauptsächlich in Dialogen benutzt, um dort im Fußbereich Buttons zum Bestätigen der Eingabe oder zum Abbrechen etc. zur Verfügung zu stellen.

Am einfachsten können Buttons mithilfe ihrer IDs (int) in die ButtonBar eingefügt werden. Die entsprechenen IDs werden dazu (bitweise) OR-verknüpft (z. B. ButtonBar.OK|ButtonBar.CANCEL) und dem Konstruktor übergeben.

Als mögliche IDs stehen zur Verfügung:

  • OK, ButtonBar.CANCEL,
  • ACCEPT, ButtonBar.CLOSE,
  • UPDATE, ButtonBar.RUN,
  • VALIDATE, ButtonBar.DELETE,
  • NONE.

Die Action-Instanzen, die zu diesen internen Button-Implementierungen gehören, kann man sich über die entsprechende get()-Methode, z. B. getOKButton() oder getCancelButton() besorgen.

Die Klasse bietet außerdem diverse add()-Methoden an, über die Buttons in gewohnter Weise in die Button-Leiste eingefügt werden können. Diese sind:

  • add(Action action),
  • add(Action action, int side) und
  • add(Button b, int side).

Ohne Angabe des Parameters „side“ werden neue Elemente immer auf der linken Seite eingefügt. Wenn der Button rechts platziert werden soll, dann ist ButtonBar.RIGHT als int-Wert zu übergeben.

Über den Konstruktor kann ein ActionListener Objekt registriert werden, welches bei jedem Auslösen eines Buttons benachrichtigt wird.

Die Definition eines so genannten „Default-Buttons“ über setDefault(int button), legt fest, welcher Button auf die Betätigung der „Eingabe“-Taste reagieren soll. Die ID der Action wird als Übergabeparameter eingesetzt. Visuell wird der Default-Button mit einer dunklen Umrahmung versehen. Defaultgemäß ist der OK-Button als solcher gekennzeichnet, wenn dieser in dem ButtonBar enthalten ist.

Mit removeAll() werden alle Buttons aus der Button-Leiste entfernt.

In Kapitel „4.3 Dialoge verwenden“ ist ein Beispiel aufgeführt, welches die Klasse ButtonBar für einen „OK“ und „Abbrechen“-Button benutzt.

3.7.3 Menu

Die Klasse com.cisag.pgm.gui.Menu dient der Realisierung von Drop-Down Menüs, wie sie typischerweise in Menüleisten verwendet (vgl. Kapitel 3.7.4 MenuBar) werden.

Drop-Down Menüs bestehen aus einer Schaltfläche (Titel) und einem Popup-Fenster mit einer Liste von Menüeinträgen (MenuItems), welches sich öffnet, wenn man die Schaltfläche aktiviert.

Die Klasse verfügt über einen leeren Konstruktor bzw. Konstruktoren der Signatur Menu(String path) bzw. Menu(Action action). Dabei wird der Text im Menütitel entweder aus dem spezifizierten Pfad ermittelt oder aus dem Action Objekt gemäß action.getText() erfragt. Bei Übergabe einer Action werden die Texte für ToolTip und Direkthilfe ebenfalls über die Action initialisiert. Die Methode getAction() liefert das im Konstruktor definierte Action Objekt.

Zum Setzen des Titels nach der Instanziierung des Objektes stehen die Methoden

  • setText(String text),
  • setTitleFrom(String path)
  • setTitleFrom(String path, String[] parameters)

zur Auswahl.

Das Füllen des Popup-Menüs kann mit unterschiedlichen add()-Methoden erfolgen. Die Methode add(Action action) fügt ein Item hinzu, welches sich wie ein Button verhält und durch Icon und Text repräsentiert wird. Die übergebene Action kommt zur Auslösung, wenn das Item ausgewählt wird (Mausklick oder ENTER-Taste). Mit addTextMenuItem(Action action) wird ein Button mit reinem Text hinzugefügt. Mit der Methode addCheckBoxMenuItem(Action action) können Menüeinträge mit CheckBox-Charakter eingefügt werden. Das Einfügen einer horizontalen Trennlinie erfolgt mit der Methode addSeparator().

Mit insert(int index, Action action) ist das Hinzufügen eines Items an einer gewünschten Position möglich. Die Items der Popup-Menüs können mit remove(int pos) bzw. removeAll() entfernt werden.

Eine Liste mit allen hinzugefügten Action Objekten gibt die Methode getSubactions() zurück. Mit getAction(int pos) erhält man die an betreffender Position eingefügte Action.

3.7.4 MenuBar

Menüleisten können über die Klasse com.cisag.pgm.gui. MenuBar erzeugt werden. Typische Semiramis-Anwendungen besitzen jedoch keine eigene Menüleiste, da durch das Anwendungsfenster eine zentrale Menüleiste bereitgestellt wird.

  • MenuBar

Das Hinzufügen von Drop-Down-Menüs erfolgt über die Methode addMenu(Menu menu), wobei jedes Menü durch eine Instanz von com.cisag.pgm.gui.Menu repräsentiert wird. Die Methode getMenus() liefert ein Array der aktuellen Menüs zurück. Mit addActionListener(ActionListener l) bzw. removeActionListener(ActionListener l) erfolgt die zentrale Registrierung bzw. Deregistrierung eines ActionListeners bei jeweils allen Menüs.

3.7.5 MessageGroupView

Die Klasse com.cisag.pgm.gui.MessageGroupView erweitert die Klasse com.cisag.pgm.gui.View um spezielle Unterstützung für Meldungsgruppen. Diese Klasse wird überwiegend dort verwendet, wo Prüfungen nicht auf Anwendungsebene, sondern z. B. auf der Ebene von einzelnen Views durchgeführt werden. Typisches Beispiel dafür sind die Zeilen von Listen (siehe 3.6.2.3 ListView).

3.8 Spezielle Elemente

3.8.1 Tree

Die Klasse com.cisg.pgm.gui.Tree dient der Visualisierung von baumartigen Strukturen.

In der nachfolgenden Abbildung wird die Verwendung der Klasse Tree am Beispiel des Anwendungsverzeichnisses von Semiramis dargestellt. Die gezeigte Struktur ist nur 1-stufig, da dort unter einem Verzeichnisknoten nur Blattelemente und keine weiteren Knoten vorkommen. Grundsätzlich erlaubt der Baum beliebig tiefe Strukturen.

  • Tree

Der Konstruktor Tree(String guid, TreeNode root, Action action, TreeViewCreator creator, EditableTreeViewCreator editableCreator) legt fest, welche Objekte für Erzeugung und Initialisierung einer Baumstruktur notwendig sind. Wie bei den meisten Elementen muss eine GUID angegeben werden. Als „root“-Element ist eine Instanz von com.cisag.pgm.gui.TreeNode (siehe 3.8.1.1 TreeNode) zu übergeben, welche bereits die gesamte Struktur enthalten kann. Auf Basis dieses Objektes wird intern ein Datenmodell für den Baum erstellt. Wird kein „root“-Knoten angegeben, erstellt der Konstruktor ein leeres Baummodell.

Über den Parameter „action“ kann eine Instanz von com.cisag.pgm.gui.Action registriert werden, deren Listener benachrichtigt werden soll, wenn der Benutzer ein Element aktiviert („öffnet“). Dieses, auch als „Open-Action“ bezeichnete Ereignis, kann durch die Tastatur („Eingabe“-Taste) oder (je nach Benutzereinstellung) durch Einfach- bzw. Doppelklick mit der Maus ausgelöst werden.

Über den Parameter „creator“ kann eine „Factory“ (com.cisag.pgm.gui.TreeViewCreator) für die Erzeugung von speziell angepassten com.cisag.pgm.gui. TreeView (siehe 3.8.1.2 TreeView) Instanzen übergeben werden. Ohne die Angabe einer solchen Factory werden die Baumknoten mit generisch erzeugten Instanzen von TreeView visualisiert.

Wenn die Baumknoten (direkt) editierbar sein sollen, dann muss über den Parameter „editableCreator“ eine entsprechende „Factory“ (com.cisag.pgm.gui.EditableTree ViewCreator) spezifiziert werden. Die Aufgabe dieser Factory ist es, entsprechend konfigurierte Instanzen von com.cisag.pgm.gui.EditableTreeView (siehe 3.8.1.3 EditableTreeView) zu erzeugen.

Die Methoden addNode(TreeNode node) bzw. addNode(TreeNode parent, TreeNode node) versehen die Baumstruktur mit weiteren Elementen, indem die Knoten ihrem Elternknoten untergeordnet werden. Der Elternknoten stammt entweder aus node.getParent() bzw. wird explizit angegeben. Kann kein Elternknoten identifiziert werden, wird das TreeNode Objekt dem „root“-Knoten zugefügt. Die Funktion insertNode(TreeNode aheadOf, TreeNode node) fügt das neue Element („node“) unmittelbar vor dem Knoten- bzw. Blattelement „aheadOf“ ein. Beide haben dann denselben Elternknoten.

Ein neuer „root“-Knoten kann dem Baum mit setRoot(TreeNode node) bzw. mit setRoot(String data) gesetzt werden, wobei im letzteren Fall anhand des Parameters „data“ das TreeNode Objekt automatisch erstellt wird. Die Methode getRoot() liefert den aktuellen Wurzelknoten zurück.

Mit der Methode removeNode(TreeNode node) wird ein Knoten entfernt, removeChildren(TreeNode parent) löscht alle Unterknoten des angegebenen Elternelements und removeAll() leert die gesamte Baumstruktur.

Die Methode findNode(byte[] guid) bietet die Möglichkeit einen Knoten anhand seiner GUID zu suchen.

Das Aufklappen bzw. Schließen eines Baumknotens (Ordners) erfolgt aus Benutzersicht per Mausklick (linke Maustaste) auf den Knoten, wobei in den Benutzereinstellungen entweder Einfach- oder Doppelmausklick gewählt werden kann. Mit der Tastatur sind hierfür die Pfeil-Tasten „rechts“ bzw. „links“ zu betätigen.

Serverseitig stehen zum Auf-/Zuklappen der Knoten die Methoden expandNode(TreeNode node) und collapseNode(TreeNode node) bzw. expandAll() und collapseAll() zur Verfügung. Mit isExpanded(TreeNode node) und isCollapsed(TreeNode node) kann erfragt werden, in welchem Zustand sich der betreffende Knoten befindet.

Die Methoden setExpandAction(Action a) bzw. setCollapseAction(Action a) ermöglichen die Registrierung von Actions, deren ActionListener dann beim Öffnen bzw. Schließen eines Knotens benachrichtigt werden.

Die Funktion editNode(TreeNode node) schaltet den gewünschten Knoten in den Editiermodus um, falls, wie oben erläutert, ein EditableTreeViewCreator Objekt als Factory für EditableTreeView Objekte registriert wurde. Auf diese Weise kann die Bezeichnung des Knotens geändert werden.

Die Baumdarstellung erlaubt Einfach- (Defaulteinstellung) oder Mehrfachselektion, die mit setSelectionMode(int mode) angepasst werden kann. Hierfür übergibt man die Konstanten Tree.SINGLE_SELECTION bzw. Tree.MULTIPLE_SELECTION. Der oder die aktuell markierten Knoten liefern die Methoden getSelectedNode() bzw. getSelectedNodes() zurück. Ebenfalls erhält man mit dem Aufruf der Methode isSelected(TreeNode node) Information darüber, ob ein bestimmter Knoten zur Selektion gehört. clearSelection() löscht die komplette Selektion.

Des Weiteren besteht auch die Möglichkeit per setSelectionAction(Action a) eine Action zu registrieren, deren Listener bei jeder Selektionsänderung benachrichtigt werden sollen. Über action.getSource() bzw. action.getState() können die Listener in ihrer performAction()-Methode den aktuell selektierten Knoten bzw. das zugehörige Datenobjekt abfragen.

Folgende Methoden beziehen sich auf die Darstellung des Baums auf der Benutzeroberfläche. setRootVisible(boolean value) legt fest, ob der Wurzelknoten gezeigt wird. Die Voreinstellung steht auf true. Bei false sind nur die Kindknoten zu sehen. Mit setTopHandlesDisplayMode(boolean value) lassen sich die Knoten um ein zusätzliches Symbol ( bzw. ) erweitern, welches veranschaulicht, ob der Knoten geschlossen bzw. geöffnet ist und ob er überhaupt Unterknoten enthält.

Die Methode setVisibleRowCount(int newCount) legt die bevorzugte Höhe (Eigenschaft „preferredHeight“) der Baumstruktur über die Anzahl der gewünschten sichtbaren Zeilen (Knoten) fest.

Der Baum unterstützt sowohl horizontales als auch vertikales Scrolling und stellt die entsprechenden Methoden (setVerticalScrollBarPolicy(int policy), setVerticalScrollBarPolicy(int policy)) zur Einstellung der Eigenschaften zur Verfügung.

Hinweis:
In der aktuellen Version ist die Klasse noch von VisualElementContainer abgeleitet (statt von VisualElement). Die von VisualElementContainer geerbten Eigenschaften und Methoden werden von der Klasse Tree nicht unterstützt und können daher nicht genutzt werden.

3.8.1.1 TreeNode

Die Elemente (Knoten) eines Baumes werden durch Objekte der Klasse com.cisag.pgm.gui.TreeNode repräsentiert. Ihre Erzeugung erfolgt mithilfe des Konstruktors TreeNode(String text, String iconName, Object dataObject, String viewName, byte[] guid). Wobei der Parameter „text“ für die Beschriftung des Knotens verwendet wird. Über den Parameter „iconName“ kann für den Knoten ein spezielles Icon spezifiziert werden, wobei die Spezifikation in Form eines Pfades (Icon-Objekt aus dem Repository) erfolgen muss. Dem Knoten kann über den Parameter „dataObject“ ein beliebiges Objekt zugeordnet werden. In der Regel ist es das Objekt (oder eine Referenz darauf), welches durch den Knoten repräsentiert wird. Der Parameter „viewName“ kann genutzt werden, um einer entsprechenden TreeView-Factory (TreeViewCreator) einen Hinweis zu geben, wie der zugehörige TreeView konfiguriert werden soll. Der Parameter „guid“ dient zur eindeutigen Identifizierung des Knotens. Die als Parameter spezifizierten Eigenschaften sind auch über entsprechende get/set-Methoden erreichbar.

Ein ToolTip kann mit der Methode setTooltip(String text) definiert werden, ebenso eine ID für die Direkthilfe (setContextHelpID(String id)).

Der Knoten wird vom Konstruktor als reines Blattelement erzeugt. Mit der Methode setAllowsChildren(boolean allow) kann diese Eigenschaft geändert werden.

Für die Erweiterung eines Knotens um „Kindknoten“ kommen die Methoden addChild(TreeNode child) bzw. addChild(TreeNode aheadOf, TreeNode child) zum Einsatz. Der angegebenen Knoten wird als Kindknoten angehängt, wobei seine „parent“ Referenz neu gesetzt wird. Diese kann mit getParent() erfragt werden. Wenn zusätzlich ein Bezugsknoten in Form des Parameters „aheadOf“ übergeben wird, dann erfolgt das Hinzufügen des neuen Knotens direkt vor diesem Bezugsknoten.

Mit removeChild(TreeNode child) wird der gewünschte Unterknoten entfernt, removeChildren() löscht alle Unterknoten.

Folgende Methoden dienen der Analyse eines Elternknotens.

  • hasChildren() liefert true, wenn Kindelemente vorhanden sind.
  • getMaxDepth() liefert die maximale Tiefe der Verkettung der Kindkomponenten.
  • getChildren() liefert ein TreeNode[] Array, welches alle unmittelbaren Kindelemente des Knotens enthält.
  • TreeNode

Die Methode isAncestor(TreeNode node) prüft, ob der angegebene Knoten in der Elternkette vorhanden oder dem Knoten selbst entspricht. getLevel() analysiert die Tiefe der Hierarchie eines Knotens bis zum „root“-Element.

Die nächsten Nachbarknoten eines TreeNode Objektes geben die Methoden getNextNode() bzw. getPreviousNode() zurück.

Hinweis:
Das Hinzufügen oder Entfernen von Knoten sollte immer über die entsprechenden Methoden bei der Klasse Tree erfolgen. Die Klasse TreeNode verfügt zwar ebenfalls über entsprechende Methoden, allerdings führt die Verwendung dieser Methoden nicht zu einer automatischen Aktualiserung der Baumansicht. Um die Baumansicht zu aktualisieren, muss dann beispielsweise der Root-Knoten bei dem Baum neu zugewiesen werden.

3.8.1.2 TreeView

Die Klasse com.cisag.pgm.gui.TreeView wird bei Bäumen für die Visualisierung von Knoten und Blättern benutzt. Die Klasse Tree zeichnet die Elemente nicht selbst, sondern delegiert diese Aufgabe an Instanzen von TreeView. Ein TreeView ist sozusagen der „Painter“ bzw. „Renderer“ für ein TreeNode Objekt. Welches TreeView Objekt zum Zeichnen eines bestimmten TreeNodes benutzt wird, entscheidet der TreeViewCreator, der als Factory für Instanzen von TreeView dient. Über diese Konstruktion ist es möglich, für jedes TreeNode-Objekt eine spezifische Darstellung anzubieten.

Die Klasse stellt zugleich eine Default-Implementierung bereit. Diese visualisiert die Baumknoten über ein Icon und einen Text. Der Text wird mit node.getText() direkt aus dem TreeNode Objekt übernommen. Für das Icon wird node.getIconName() genutzt oder, falls beim Knoten kein eigenes Icon definiert ist, ein Standard-Icon für den jeweiligen Knotentyp und -zustand (Blatt bzw. geöffneter/geschlossener Ordner) gewählt. Die Default-Implementierung berücksichtigt bei der Darstellung auch markierte bzw. fokussierte Knoten.

Dem Konstruktor TreeView(Tree owner) ist die dazugehörige Instanz von Tree zu übergeben. Optional kann über den Konstruktor TreeView(Tree owner, int nodesize) auch eine Schriftgröße spezifiert werden, wobei entsprechende über die Konstanten (TreeView.SIZE_DEFAULT bzw. TreeView.SIZE_7PT) bereitgestellt werden.

Der Default-Konstruktor (protected) kann von Subklassen genutzt werden, die die UI-Elemente der Default-Implementierung nicht benötigen bzw. die verhindern wollen, dass diese Elemente erzeugt werden. Im Allgemeinen sollten Subklassen die Default-Implementierung nutzen und sich auf das Überschreiben der dataToUi()-Methode beschränken.

Das Mapping von Knoteneigenschaften auf entsprechende UI-Elemente (Icon, Text) erfolgt in der Methode dataToUi(TreeNode node). Subklassen von TreeView können diese Methode überschreiben, um ihre eigenen UI-Elemente mit Daten zu versorgen und/oder um andere Eigenschaften des Knotens oder seines Datenobjektes zu berücksichtigen. Der Zugriff auf die Default-Implementierung für Text und Icon ist über die (protected) Variablen label bzw. iconField möglich. Es wird empfohlen, zu Beginn super.dataToUi(TreeNode node) aufzurufen, damit die Farben, Rahmen und Schriften durch die Default-Implementierung eingestellt werden.

3.8.1.3 EditableTreeView

Die Klasse com.cisag.pgm.gui.EditableTreeView wird bei Bäumen für die Bearbeitung von Knoten und Blättern benutzt, insbesondere zum Bearbeiten des Knotennames. Die Klasse Tree bearbeitet die Elemente nicht selbst, sondern delegiert diese Aufgabe an Instanzen von EditableTreeView. Ein EditableTreeView ist sozusagen der „Editor“ für ein TreeNode Objekt. Welches EditableTreeView Objekt zum Editieren eines TreeNodes benutzt wird, entscheidet der EditableTreeViewCreator, der als Factory für Instanzen von EditableTreeView dient. Analog zu den TreeViews (siehe 3.8.1.2 TreeView) erlaubt diese Konstruktion, jedes TreeNode-Objekt mit einem spezifischen Editor zu bearbeiten.

Hinweis:
Der EditableTreeView und der TreeView für ein TreeNode Objekt sollten aufeinander abgestimmt sein, d. h. der Aufbau, die Größe und die Position der Subelemente sollten, bis auf das Element, welches zum Editieren benutzt wird, übereinstimmen.

Die Klasse stellt zugleich eine Default-Implementierung bereit, diese unterscheidet sich von der Implementierung von TreeView nur insofern, dass für die Bearbeitung des Textes ein TextField (statt Label) benutzt wird.

3.8.2 HTMLPane

Die Klasse com.cisag.pgm.gui.HTMLPane kann dazu benutzt werden, um HTML-Inhalte in die Oberfläche zu integrieren. Als Quelle für die HTML-Inhalte kommen folgende Möglichkeiten in Betracht:

  • „Einfacher“ HTML-Text.
  • Eine URL, über die eine HTML-Seite, ein Image oder auch ein beliebiges Dokument geladen werden kann.
  • Eine Instanz von cisag.pgm.gui.HTMLDocument.
  • Eine Instanz von cisag.pgm.gui.ImageDocument.

Die erste Möglichkeit bietet sich an, wenn es nur darum geht formatierten Text ausgeben zu wollen. Der Text kann direkt mit setText(String text) gesetzt werden. Bei den verwendeten HTML-Tags ist zu beachten, dass sie innerhalb eines <DIV>-Elements erlaubt sein müssen (z. B. sind die Elemente <HTML>, <META>, <BODY> etc. dort nicht zulässig) und dass sie nicht Browser-spezifisch sein sollten. Selbstverständlich muss die Syntax der Elemente und Attribute korrekt sein, einschließlich der korrekten Paarung von öffnenden und schliessenden Tags und dem „Escapen“ von Sonderzeichen[33]. Auf die Verwendung/Referenzierung von anderen Dokumenten (Elemente mit den Attributen href bzw. src) sollte verzichtet werden, ebenso auf die Verwendung von Formularelementen (<FORM>, <INPUT>, etc.) und Scripten.

Die zweite Möglichkeit bietet sich an, wenn Dokumente oder Bilder eingebettet werden sollen. Die URLs sollten das „https“-Protokoll verwenden[34]. Typischerweise wird diese Möglichkeit zum Einbetten von Dokumenten aus dem KnowledeStore benutzt. Das Setzen der URL sollte über die Methode setURL(String url) erfolgen. Das Setzen der URL über den Konstruktor HTMLPane(String) wird nicht empfohlen, da diese Signatur künftig für die Zuweisung einer GUID verwendet werden soll.

Die dritte und vierte Möglichkeit sind im Grunde nur Varianten der zweiten Möglichkeit. Der Unterschied besteht darin, dass das einzubettende Dokument nicht über eine URL referenziert wird, sondern im Hauptspeicher als Char- bzw. Byte-Array vorliegt (z. B. weil es auch dort generiert bzw. „berechnet“ wurde). Aus dem Char- bzw. Byte-Array ist zunächst eine Instanz von HTMLDocument bzw. ImageDocument zu erzeugen, diese kann dann bei dem HTMLPane mit setDocument(HTMLDocument document) gesetzt werden. Die Klasse ImageDocument sollte immer dann verwendet werden, wenn es sich bei den Daten um ein Bild (*.png, *.gif, *.jpg, …) handelt.

Das HTMLPane unterstützt nach Bedarf horizontales und vertikales Scrolling.

3.8.3 HTMLEditor

Die Klasse com.cisag.pgm.gui.HTMLEditor stellt einen einfachen Texteditor für formatierten (HTML)-Text dar.

Zu dem Editor gehört auch eine Symbolleiste mit typischen Werkzeugen, z. B. für die Auswahl von Schriftart, Schriftgröße, Farbe und Textausrichtung.

Über den Konstruktor HTMLEditor(String guid) wird ein Editor mit Symbolleiste erzeugt. Mit den Methoden setColorSupported(boolean supported) bzw. setFontSupported(boolean supported) können bestimmte Werkzeuge bzw. Auswahlelemente ausgeblendet werden.

Zusätzliche Elemente lassen sich in die Symbolleiste mithilfe von addCoolBarElement(VisualElement element, int side) einfügen. Hierbei ist anzugeben, an welcher Seite (Coolbar.LEFT bzw. Coolbar.RIGHT) der Leiste das neue Element platziert werden soll. Bei linksseitigem Einfügen wird ein Separator als vertikaler Trennstrich dazwischengelegt. Mit removeCoolBarElement(VisualElement element) kann das eingefügte Element wieder entfernt werden.

  • HTMLEditor

Die Methode setText(String text) erlaubt die serverseitige Definition des Inhalts. Für den übergebenen HTML-Text gelten die selben Regeln wie für das HTMLPane (siehe 3.8.2 HTMLPane). Die Methode getText() liefert den aktuellen HTML-Text des Editors zurück.

3.8.4 PopupMenu

Die Klasse com.cisag.pgm.gui.PopupMenu zeigt eine Liste von Menüeinträgen in einem Popup-Fenster an. Üblicherweise werden solche Popup-Menüs als Kontextmenüs verwendet und werden z. B. über die rechte Maustaste geöffnet.

In der nachfolgenden Abbildung ist ein typisches Kontextmenü für ein EntityField dargestellt.

Hinweis:
Bei EntityFields wird das Kontextmenü automatisch, d. h. vom System, bereitgestellt (siehe 3.5.4 EntityField), die explizite Erzeugung bzw. Konfiguration eines Popup-Menüs ist nicht notwendig.

  • Pop-up-Menü

Die Instanziierung eines PopupMenu Objektes erfolgt über den Konstruktor PopupMenu().

Für das Hinzufügen von Menüeinträgen stehen verschiedene add()-Methoden zur Verfügung. Typischerweise wird jedoch die Methode add(Action action) verwendet, diese erzeugt aus der übergebenen Action einen entsprechenden Menüeintrag und übernimmt Icon, Text, ToolTip und Direkthilfe aus der Action.

Menüeinträge, die kein Icon erhalten sollen, können mit addTextMenuItem(Action action) dem Menü zugefügt werden. Die Methode addCheckBoxMenuItem(Action action) dient dem Hinzufügen von Menüeinträgen mit CheckBox-Charakter. Trennlinien (Separatoren) können mit der Methode addSeparator() hinzugefügt werden.

Wenn die neuen Menüeinträge nicht am Ende, sondern an einer bestimmten Position eingefügt werden sollen, dann können die Methoden insert(int index, Action action) bzw. insertSeparator(int index) genutzt werden. Die Methode remove(int pos) entfernt einen bestimmten Menüeintrag und removeAll() entfernt alle Menüeinträge.

Die mit einem bestimmten Menüeintrag verbundene Instanz von Action lässt sich über die Methode getAction(int pos) ermitteln. Analog liefert getPosition(Action action) den Index einer bestimmten Action zurück. Mit getSubactions() erhält man alle Actions in Form eines Arrays zurück.

3.8.5 Glue

Ein „Glue“ ist ein unsichtbares grafisches Hilfselement, welches benutzt wird, um Leerräume in einem Container auszufüllen, damit diese nicht von anderen Elementen besetzt werden können.

Glues werden überwiegend in Containern mit BoxLayout Layout-Manager (siehe 3.9.3 BoxLayout) verwendet. Wenn in einem Container mehr Platz zur Verfügung steht, als von dessen Elementen (laut prefferedWidth bzw. preferredHeight) benötigt wird, so verteilt das BoxLayout den überschüssigen Platz auf die Elemente, deren maximumWidth bzw. maxiumHeight dies zulässt.

Wenn dieser Platz an einer bestimmten Stelle (z. B. am linken Rand des Containers oder in der Mitte zwischen den regulären Elementen) soll, dann kann an dieser Stelle ein Glue eingefügt werden. Damit das Glue den gesamten Platz einnimmt, sollte die maximumWidth bzw. maximumHeight der anderen Elemente auf die jeweilige preferredWidth bzw. preferredHeight beschränkt sein, ansonsten würde der freie Platz auch auf diese Elemente verteilt werden.

Das Verhalten des Glues begründet sich allein auf der Tatsache, dass die Eigenschaften minimumWidth, minimumHeight, preferredWidth und preferredHeight den Wert „0“ besitzen und mindestens eine der Eigenschaften maximumWidth bzw. maximumHeight einen sehr großen Wert (Short.MAX_VALUE) hat.

Über den Konstruktor Glue(int type) wird festgelegt, in welche Richtung sich das Element ausdehnen darf. Mögliche Werte sind Glue.HORIZONTAL, Glue.VERTICAL oder Glue.BOTH. Obwohl der letztgenannte Wert auch dem Verhalten des Default-Konstruktors entspricht, sind 2-dimensionale Glues in den meisten Anwendungsfällen nicht sinnvoll. Es sollte je nach Ausrichtung des BoxLayouts immer ein Glue mit gleicher Ausrichtung verwendet werden.

Ein Beispiel für die Verwendung von Glues ist in Kapitel 3.9.3 BoxLayout

zu finden.

3.8.6 Strut

Ein „Strut“ stellt ein unsichtbares grafisches Hilfselement mit einer definierten Größe entweder in horizontaler oder vertikaler Richtung dar.

Ähnlich wie ein Glue, wird ein Strut überwiegend in Containern mit BoxLayout Layout-Manager (siehe 3.9.3 BoxLayout) verwendet und kann dort als „Abstandshalter“ zwischen zwei Elementen genutzt werden.

Das Verhalten des Struts wird dadurch erreicht, dass je nach Ausrichtung entweder die Eigenschaften minimumWidth, preferredWidth und maximumWidth bzw. die Eigenschaften minimumHeight, preferredHeight und maximumHeight den gewünschten Wert für den Abstand aufweisen. In der jeweils anderen Richtung sind der minmale und der bevorzugte Werte dann „0“ und der maximale Wert ist Short.MAX_VALUE[35].

Im Konstruktor Strut(int type) muss die gewünschte Ausrichtung angegeben werden. Mögliche Werte sind Strut.HORIZONTAL bzw. Strut.VERTICAL. Die Ausrichtung des Strut sollte dabei immer mit der des Containers (d. h. BoxLayout) übereinstimmen. Der Standardwert für die Breite bzw. Höhe liegt bei 5 Pixel. Wenn eine andere Breite/Höhe benötigt wird, dann kann diese über den Konstruktor Strut(int type, int size) festgelegt werden.

Ein Beispiel für die Verwendung von Struts ist in Kapitel 3.9.3 BoxLayout zu finden.

3.9 Layout-Manager

Die Anordnung von Elementen erfolgt durch Layout-Manager auf der Ebene von Containern (VisualElementCon-tainer). Jedem Container in der Container-Hierarchie ist eine eigene Instanz eines Layout-Managers zuzuordnen, d. h. ein Layout-Manager übernimmt das Layout immer nur für die direkten Elemente eines Containers. Wenn ein Subelement selbst ein Container ist, dann benötigt dieser einen eigenen Layout-Manager.

In dem Package com.cisag.pgm.gui stehen verschiedene Layout-Manager zur Auswahl:

  • cisag.pgm.gui.BorderLayout
  • cisag.pgm.gui.BoxLayout
  • cisag.pgm.gui.FlowLayout
  • cisag.pgm.gui.StandardLayout
  • cisag.pgm.gui.XYLayout

In Semiramis-Anwendungen werden vorwiegend nur

  • das StandardLayout,
  • das BoxLayout und
  • das BorderLayout

verwendet.

Jeder der genannten Layout-Manager verwendet eine für ihn typische Layout-Strategie. Diese Strategie betrifft sowohl die logische Platzierung, d. h. die relative Positionierung der Elemente zueinander, als auch das Verhalten bei Platzmangel oder bei Platzüberschuss. Der Layout-Vorgang wird von dem UI-Framework automatisch angestoßen, wenn sich die Fenstergröße oder andere Layout-relevante Eigenschaften (z. B. die bevorzugte Größe) eines Elements geändert haben.

Im Allgemeinen nutzt ein Layout-Manager folgende Informationen für die Positionierung und Größenberechnung eines Elements:

  • Die aktuelle Größe des Containers.
  • Die Breite von Rahmen (Border) bzw. Randabständen (Margins) im Container.
  • Die Position (Index) des jeweiligen Elements im Container.
  • Die bei „add“ verwendeten Constraints.
  • Die Eigenschaften miniumWidth/-height, preferredWidth/-height, maxiumWidth/-height der Elemente.
  • Die Eigenschaften alignmentX/-Y der Elemente.

Je nach Strategie nutzen einige Layout-Manager jedoch nur einen Teil dieser Informationen oder betrachten sie nur als „Wunsch“, der aufgrund von Restriktionen oder anderen „Wünschen“ nicht immer oder nur näherungsweise erfüllt wird.

Einige Layout-Manager besitzen auch eigene Eigenschaften, über die das Layout beeinflusst werden kann, z. B.:

  • Ausrichtung (horizontal, vertikal)
  • Abstände („gaps“) zwischen Elementen
  • „Zeilenabstand“

Das StandardLayout (siehe 3.9.1 StandardLayout) nutzt darüberhinaus auch (Container-übergreifende) Führungslinien (Spalten) für die Ausrichtung der Elemente.

Eine weitere Aufgabe der Layout-Manager ist es, die Eigenschaften miniumWidth/-height, preferredWidth/-height, maxiumWidth/-height sowie alignmentX/-Y für den Container zu berechen. Der Container kann diese Werte nicht selbst berechnen, da sie von der Layout-Strategie des jeweiligen Layout-Managers abhängig sind.

Da Container mit unterschiedlichen Layouts beliebig ineinander verschachtelbar sind, stehen dem Anwendungsentwickler praktisch alle Möglichkeiten offen, Elemente nach seiner Vorstellung anzuordnen.

Constraints

Die Constraints geben dem Layout-Manager zusätzliche Informationen darüber, wo oder wie ein bestimmtes Element platziert werden soll. Ob ein Layout-Manager Constraints benötigt bzw. wie diese aufgebaut sein müssen, hängt von dem jeweiligen Layout-Manager ab. So benötigt und „versteht“ das BoxLayout z. B. überhaupt keine Constraints, das BorderLayout erwartet hingegen die Angabe einer logischen Position in Form der Konstanten BorderLayout.CENTER, BorderLayout.NORTH, usw. Das StandardLayout wiederum benötigt typischerweise nur die Angabe einer Spaltennummer, erlaubt aber für Spezialfälle auch die Verwendung eines speziellen Parameterobjektes (com.cisag.pgm.gui.ReferenceConstraints).

Die Spezifikation bzw. die Übergabe der Constraints für ein Element erfolgt beim Hinzufügen dieses Elements zu einem Container (als zusätzlicher Parameter der „add“-Methode). Entscheidend ist dabei, dass dem Container zuvor ein passender Layout-Manager zugeordnet wurde.

3.9.1 StandardLayout

Das StandardLayout (com.cisag.pgm.gui.Standard-Layout) ist, wie der Name schon andeutet, der am häufigsten genutzte Layout-Manager in Semiramis-Anwendungen. Seine Layout-Strategie ist speziell für die zeilenorientierte und mehrspaltige Anordnung von Feldern (inkl. Label) ausgelegt.

Vertikal arbeitet der Layout-Manager mit einem Zeilenraster (Eigenschaft rowHeight), an dem die Elemente ausgerichtet werden. Den Elementen wird grundsätzlich ihre bevorzugte Höhe (preferredHeight) gewährt. Der Startpunkt für die nächste Zeile ergibt sich dann aus dem höchsten Element der aktuellen Zeile, wobei dieser Startpunkt noch an das Zeilenraster angepasst wird (nächster durch „rowHeight“ teilbarer Wert).

Die horizontale Ausrichtung erfolgt über Führungslinien (Guides). Die Definition von Führungslinien und die Verwendung dieser Führungslinien durch das StandardLayout sind grundsätzlich voneinander unabhängig. Führungslinien sollten nach Möglichkeit nur einmal, und zwar „möglichst weit oben“ in der Container-Hierarchie definiert werden. Die Führungslinien sind für jeden Subcontainer (rekursiv) sichtbar, unabhängig davon, ob einige Zwischencontainer einen anderen Layout-Manager nutzen oder nicht. Eine Neudefinition von Führungslinien ist nur sinnvoll, wenn ein Subcontainer tatsächlich andere Führungslinien benötigt als er von „oben erben“ kann, z. B. wenn der Subcontainer fünf Spalten statt 2 Spalten verwenden soll.

Hinweis:
Bei der Verwendung des StandardLayouts ist zu beachten, dass die nicht leeren Konstruktoren immer mit der Neudefinition von Führungslinien verbunden sind.

Die Definition der Führungslinien erfolgt indirekt über die Definition von Spalten, wobei für eine Spalte bis zu 6 Führungslinien verwendet werden:

  • Beginn der Spalte
  • Beginn des Labels
  • Ende des Labels
  • Beginn des Feldes
  • Ende des Feldes
  • Ende der Spalte

Die Definition von Spalten bzw. Führungslinien sollte grundsätzlich nur über die setGuides() Methoden von VisualElementContainer bzw. die setColumnWidths() Methoden bei Listen[36] erfolgen[37]. Im einfachsten Fall ist dabei nur die gewünschte Anzahl von Spalten zu übergeben. Es ist auch möglich die Breite der einzelnen Spalten oder sogar die Abstände zwischen den Spalten zu spezifizieren (siehe Spalten definieren).

Die nachfolgende Abbildung zeigt eine GroupBox mit StandardLayout. In der GroupBox liegen vier Felder und ein „Subshelf“ mit fünf Feldern. Das Subshelf hat ebenfalls ein StandardLayout als Layout-Manager. Die Felder in der GroupBox und in dem Subshelf werden (obwohl sie in unterschiedlichen Containern liegen) an denselben Führungslinien ausgerichtet.

  • Standard Layout

Zur Erzeugung einer Instanz von StandardLayout sollte immer nur der Default-Konstruktor (keine Parameter) verwendet werden[38]. Nachdem diese Instanz bei einem Container (z. B. mit setLayout()) als Layout-Manager gesetzt wurde, können dem Container die Subelemente hinzugefügt werden. Der „add“-Methode ist die gewünschte Spaltennummer als Constraints mitzugeben. Spaltennummern werden von „0“ bis „n-1“ gezählt und sind als String zu übergeben. Das folgende Beispiel fügt ein Feld in die zweite Spalte ein:

container.add(field, “1”);

Wenn sich ein Element über mehr als eine Spalte erstrecken soll, dann ist die Nummer der Start- und Endspalte getrennt durch Bindestrich (Minuszeichen) als Constraints zu übergeben. Das folgende Beispiel fügt ein Feld in die ersten beiden Spalten ein:

container.add(field, “0-1”);

Die folgende Tabelle zeigt die möglichen Constraints:

Constraints Auswirkung
“i” Element wird in Spalte i eingefügt, wobei gilt:
0 <= i < N
“i-j” Element wird in die Spalten i bis j eingefügt, wobei gilt:
0 <= i <= j < N
“i-“ Element wird in die Spalten i bis N-1 eingefügt, wobei gilt:
0 <= i < N
“i:k” Element wird ab Spalte i über k Spalten bzw. bis Spalte i+k-1 eingefügt, wobei gilt:
0 <= i <= i+k-1 < N
SPAN_ALL_COLUMNS Element erstreckt sich über „alle“ Spalten

 

Spalten definieren

Obwohl das StandardLayout über entsprechende Konstruktoren zur Definition von Spalten bzw. Führungslinien verfügt, sollten diese nicht länger dazu benutzt werden. Stattdessen sollten die setGuides() Methoden von VisualElementContainer genutzt werden.

Bei Verwendung der Methode setGuides(double[] labelWidth, double[] fieldWidth, double[] leftMargins, double[] rightMargins) können die Führungslinien über die Breiten bzw. Abstände frei definiert werden. Das Array labelWidth definiert die Breiten der Label pro Spalte und das Array fieldWidth definiert die Breiten der Felder pro Spalte. Die Werte müssen jeweils relativ zur Gesamtbreite des Containers angegeben werden. Wenn beispielsweise 2 Spalten gewünscht werden und die Labels 30 Prozent von der verfügbaren Spaltenbreite bekommen sollen, so sollten die beiden Arrays wie folgt berechnet werden:

double wColumn = 1.0 / 2.0;    // two columns

double wLabel  = wColumn*0.3;  // 30 percent

double wField  = wColumn – wLabel;

double[] labelWidth = {wLabel, wLabel};

double[] fieldWidth = {wField, wField};

Die Summe aller Breiten sollte immer den Wert „1“ ergeben, wobei nur die Breiten für Label und Felder berücksichtigt werden, aber nicht die Abstände (Margins).

Über die Arrays leftMargins bzw. rightMargins können pro Spalte zusätzliche Abstände am linken bzw. rechten Rand definiert werden. Hier erfolgt die Angabe der Werte in „Pixel“.

Weitere Eigenschaften festlegen

Die Eigenschaft stretchElementsToColumnWidth hat als Voreinstellung den Wert true. Das sorgt dafür, dass alle Elemente, unabhängig von ihrer gewünschten maximalen Breite (getMaximumWidth()) auf die jeweilige Spaltenbreite verbreitert werden. Wenn diese Eigenschaft hingegen auf false gesetzt wird, dann werden die Maximal-werte entsprechend berücksichtigt.

Die Methode setRowHeight(int rowHeight) erlaubt es, die Höhe der Zeilen festzulegen. Die Voreinstellung für diesen Wert beträgt 20 Pixel.

Mithilfe der Methode setVgap(int vgap) lässt sich zwischen die Zeilen ein zusätzlicher Abstand einfügen. getVgap() liefert den Abstand zurück. Die Voreinstellung für diesen Wert beträgt „0“.

In Kapitel 3.9.1 StandardLayout ist ein Beispiel für die Verwendung von StandardLayouts zu finden.

3.9.1.1 ReferenceConstraints

Die Klasse com.cisag.pgm.gui.ReferenceConstraints dient als „Constraints“-Objekt für das StandardLayout. Während die einfachen String-basierten Constraints sich immer auf den einfachen Fall beziehen, dass ein Element in eine oder mehrere Spalten eingefügt werden soll, können mit den ReferenceConstraints auch komplexere Layouts erzielt werden. So lässt sich z. B. mit folgendem Code ein Icon rechts (mit 2 Pixel Abstand) neben ein Feld platzieren:

container.add(icon, new ReferenceConstraints(field,
ReferenceConstraints.RIGHT_OF, 2));

3.9.2 BorderLayout

Die Klasse com.cisag.pgm.gui.BorderLayout entspricht in ihrem Verhalten (Layout-Strategie) der gleichnamigen Klasse aus java.awt. Der Layout-Manager definiert fünf Bereiche:

  • „CENTER“ (Mitte),
  • „NORTH“ (oben),
  • „EAST“ (rechts),
  • „SOUTH“ (unten) und
  • „WEST“ (links).
  • BorderLayout

Beim Hinzufügen eines Elements zu einem Container mit BorderLayout ist der entsprechende Zielbereich als Contstraints anzugeben. Beispiel:

container.add(element, BorderLayout.CENTER);

Hinweis:
In einem Bereich darf maximal ein Element liegen. Wenn ein neues Element in den Bereich eingefügt werden soll, dann muss das alte Element zuvor mit remove() entfernt werden.

Die Bereiche legen bereits die relative Position der Elemente zueinander fest. Für die Größe der Elemente verwendet das BorderLayout folgende Strategie[39]:

  • Die Elemente in NORTH und SOUTH bekommen ihre bevorzugte Höhe (preferredHeight). Unabhängig davon, ob diese Höhe tatsächlich zur Verfügung steht.
  • Die Elemente in NORTH und SOUTH bekommen die gesamte Container-Breite zugeteilt. Unabhängig davon was sie als minimale, bevorzugte oder maximale Breite zurückliefern.
  • Die Elemente in WEST und EAST bekommen ihre bevorzugte Breite (preferredWidth). Unabhängig davon, ob diese Breite tatsächlich zur Verfügung steht.
  • Die Elemente in WEST und EAST bekommen die verbleibende Container-Höhe zugeteilt, also den Teil der nicht von NORTH bzw. SOUTH belegt ist. Hier erfolgt die Vergabe wieder unabhängig davon, was die Elemente als minimale, bevorzugte oder maximale Höhe zurückliefern.
  • Das Element in CENTER bekommt den gesamten verbliebenden Platz. Unabhängig davon, was das Element selbst als minimale, bevorzugte oder maximale Breite/Höhe definiert.

Hinweis:
Da die Elemente in NORTH und SOUTH ihre preferredHeight auch bekommen, wenn der Container nicht über die notwendige Höhe verfügt, kann es vorkommen, dass sich die beiden Elemente überlappen[40]. Wenn ein Element größer als der Container ist, so wird es an der Containergrenze „abgeschnitten“ („geclippt“). Die Verwendung eines BorderLayouts ist also nur sinnvoll, wenn sichergestellt werden kann, dass die preferredHeight der Elemente in NORTH bzw. SOUTH nicht die verfügbare Höhe im Container übersteigt. Dieses Verhalten gilt analog auch für WEST und EAST, nur dass dort die Breite und nicht die Höhe das Problem darstellt.

Typischerweise werden nicht alle fünf Bereiche mit Elementen gefüllt, häufig sogar nur einer (CENTER). An der oben geschilderten Layout-Strategie ändert sich dadurch jedoch nichts: Ein nicht vorhandenes (oder visible==false) Element, verhält sich ähnlich wie ein Element dessen bevorzugte Breite und Höhe gleich „0“ ist.

Die Klasse BorderLayout besitzt nur den Konstruktor BorderLayout(). Es stehen zusätzlich noch die Eigenschaften „hgap“ und „vgap“ zur Verfügung. Über diese Eigenschaften kann zwischen den Bereichen NORTH/CENTER/SOUTH bzw. WEST/CENTER/EAST ein zusätzlicher Abstand eingefügt werden.

Hinweis:
Das Verhalten des BorderLayouts lässt sich auch mithilfe des BoxLayouts erreichen, wobei die Layout-Strategie insbesondere über die Eigenschaften preferredWidth/-Height bzw. maximumWidth/-Height der Elemente gesteuert werden kann. Durch geeignete Werte für minimumWidth/-Height lassen sich zudem die oben geschilderten Nachteile des BorderLayouts umgehen. Das BoxLayout arbeitet jeweils nur horizontal oder vertikal. Es lassen sich aber bei Bedarf auch zwei Container ineinander schachteln.

3.9.3 BoxLayout

Die Klasse com.cisag.pgm.gui.BoxLayout entspricht in ihrem Verhalten (Layout-Strategie) der gleichnamigen Klasse aus javax.swing. Die Strategie dieses Layout-Managers besteht darin, alle Elemente eines Containers in einer Reihe anzuordnen. Die Ausrichtung dieser Reihe kann dabei entweder horizontal oder vertikal sein. Nach dem „Baukastenprinzip“ lassen sich jedoch verschieden ausgerichtete BoxLayouts ineinander schachteln.

 

  • BoxLayout in vertikaler Richtung

Das BoxLayout benötigt keine Constraints, sondern arbeitet ausschließlich mit den Elementeigenschaften (minimumWidth/-Height, preferredWidth/-Height, maximumWidth/-Height und alignmentX/-Y), die je nach gewählter Ausrichtung entsprechend ausgewertet werden.

In der gewählten Hauptrichtung werden die Elemente einfach nebeneinander (bzw. untereinander) platziert. Typischerweise bekommen die Elemente dabei ihre preferredWidth (bzw. preferredHeight). Wenn in dem Container mehr Platz vorhanden ist, als die Elemente gemäß ihrer „preferredWidth“ (bzw. preferredHeight) benötigten, so werden diejenigen Elemente vergrößert, deren „maximumWidth“ (bzw. maximumHeight) dies zulässt. Kommen mehrere Elemente in Frage, so wird der überschüssige Platz auf diese Elemente (proportional und unter Berücksichtigung ihrer maximalen Größe) verteilt. Ähnlich verhält es sich, wenn der Container nicht groß genug ist, um alle Elemente gemäß ihrer „preferredWidth“ (bzw. preferredHeight) darzustellen. In diesem Fall werden diejenigen Elemente verkleinert, deren „minimumWidth“ (bzw. minimumHeight) dies zulässt. Sollten mehrere Elemente für eine Verkleinerung in Frage kommen, so werden diese gemeinsam (proportional und unter Berücksichtigung ihrer minimalen Größe) verkleinert. Wenn sich die Elemente nicht weit genug verkleinern lassen, dann werden sie ggf. durch den Containerrand „abgeschnitten“.

Das BoxLayout platziert die Elemente nicht nur in der gewählten Hauptrichtung, sondern auch in der jeweils anderen Dimension. Die, durch die Eigenschaft alignmentY (bzw. alignmentX) definierten, (relativen) Bezugspunkte werden dazu genutzt, um die Elemente in vertikaler (bzw. horizontaler) Richtung aneinander auszurichten. Bezüglich der Anpassung an die Containerhöhe (bzw. -breite) gelten ähnliche Regeln wie für Hauptrichtung, d. h. ein Element wird nur dann vergrößert/verkleinert, wenn dies gemäß maximumHeight/minimumHeight (bzw. maximumHeight/minimumHeight) zulässig ist. Die Tatsache, dass ein Element als maximumHeight (bzw. maximumWidth) den Wert Short.MAX_VALUE liefert, bedeutet aber nicht automatisch, dass dieses Element den Container über seine gesamte Höhe (bzw. Breite) ausfüllt. Hier spielt auch die Eigenschaft alignmentY (bzw. alignmentX) eine Rolle, da natürlich die relative Ausrichtung zu anderen Elementen trotz Vergrößerung erhalten bleiben muss.

Hinweis:
Die Bedeutung von alignmentY (bzw. alignmentX) wird häufig missverstanden. Sie definiert nicht, wie die Elemente in Bezug auf den Container auszurichten sind, sondern wie die Elemente untereinander auszurichten sind. Die Eigenschaft alignmentY definiert einen relativen Bezugspunkt zwischen Elementoberkante (0.0f) und Elementunterkante (1.0f)[41]. Analog definiert die Eigenschaft alignmentX einen relativen Bezugspunkt zwischen linker (0.0f) und rechter (1.0f) Elementkante. Die Ausrichtung an diesen Bezugspunkten bedeutet, dass die Elemente im Container so gegeneinander verschoben werden, dass ihre Bezugspunkte auf einer Linie liegen.

Für die meisten Anwendungsfälle gilt, dass die Eigenschaft alignmentY (bzw. alignmentX) bei allen Elementen im Container den gleichen Wert liefern sollte. Das Mischen von z. B. VisualElement.CENTER und VisualElement.LEFT ist zwar zulässig (siehe oben), erfolgt aber meist unbeabsichtigt (z. B. durch unterschiedliche Voreinstellungen bei den Elementen) und liefert demzufolge unerwartete Ergebnisse.

3.9.4 FlowLayout

Bei der Klasse com.cisag.pgm.gui.FlowLayout handelt es sich um einen einfachen Layout-Manager, der die Elemente des Containers zeilenweise platziert. Die Elemente bekommen dabei jeweils ihre bevorzugte Breite und der LayoutManager beginnt automatische eine neue Zeile, wenn eine Zeile „voll“ ist.

In Semiramis-Anwendungen wird dieser Layout-Manager praktisch nicht verwendet.

3.9.5 XYLayout, XYConstraints

Die Klasse com.cisag.pgm.gui.XYLayout dient für die Fälle, in denen man die Elemente eines Containers manuell platzieren möchte. Die Klasse arbeitet wie ein Layout-Manager, jedoch besteht seine „Strategie“ lediglich darin, die vom Programmierer als XYConstraints spezifizierten Koordinaten und Größen bei den Elementen zu setzen.

Dieses Verfahren ist nur Spezialaufgaben geeignet, da sich die layouteten Container und Elemente weder an die Größe des Containers, noch an die Bildschirmauflösung oder Schriftgröße anpassen. In Semiramis-Anwendungen wird dieser Layout-Manager praktisch nicht verwendet.

3.10 Gestaltungskomponenten

3.10.1 Border

Alle Elemente (siehe 3.1.1 VisualElement) können mit einem Rahmen versehen werden (VisualElement#setBorder(Border)). Einige Elemente, wie z. B. Felder, Buttons und GroupBoxen, verfügen von sich aus über einen Rahmen. Diese Rahmen sollten i.d.R.  auch nicht geändert werden (im Sinn einer einheitlichen Oberfläche). Das explizite Verwenden von Rahmen erfolgt in Semiramis typischerweise nur in Listen, um dort die Zeilen voneinander zu trennen.

In dem Package com.cisag.pgm.gui stehen verschiedene Implementierungen von com.cisag.pgm.gui.Border zur Auswahl:

  • cisag.pgm.gui.CompoundBorder
  • cisag.pgm.gui.DecoratedBorder
  • cisag.pgm.gui.EmptyBorder
  • cisag.pgm.gui.LineBorder

Die folgenden Klassen sind hingegen veraltet bzw. entsprechen nicht den Styleguides von Semiramis und sollten nicht benutzt werden[42]:

  • cisag.pgm.gui.EtchedBorder
  • cisag.pgm.gui.LoweredBevelBorder
  • cisag.pgm.gui.RaisedBevelBorder
  • cisag.pgm.gui.RidgeBorder

3.10.1.1 LineBorder

Die Klasse com.cisag.pgm.gui.LineBorder kann genutzt werden, um ein Element mit einer einfarbigen, durchgezogenden Linie zu umranden. Je nach gewähltem Konstruktor lässt sich Farbe und Stärke der Linie auswählen. Die Linienstärke lässt sich bei Bedarf auch für jede der vier Seiten getrennt wählen. Der Wert „0“ bedeutet dabei, dass an der betreffenden Seite keine Linie gezeichnet wird.

  • LineBorder

3.10.1.2 DecoratedBorder

Die Klasse com.cisag.pgm.gui.DecoratedBorder bietet verschiedene Rahmenstile an. Zusätzlich lassen sich Farbe und Stärke des Rahmens wählen. Der Rahmen wird für alle vier Seiten des Elements benutzt. Es ist möglich, mithilfe der Klasse CompoundBorder einen Rahmen aus mehreren DecoratedBorders zusammenzusetzen.

Für die Erzeugung von DecoratedBorder-Instanzen stehen neben entsprechenden Konstruktoren auch statische Methoden zur Verfügung (create*Border()).

  • DecoratedBorder

3.10.1.3 CompoundBorder

Mithilfe der Klasse com.cisag.pgm.gui.CompoundBorder ist es möglich, einen Rahmen aus anderen Rahmen zusammenzusetzen. Jeder Seite des Rahmens wird dabei eine Instanz von DecoratedBorder zugeordnet. So lässt sich z. B. für jede Seite ein anderer Stil, eine andere Farbe und/oder eine andere Stärke verwenden. Ebenso kann statt einer Instanz von DecoratedBorder auch null verwendet werden, in diesem Fall wird an der betreffenden Seite kein Rahmen gezeichnet.

  • CompoundBorder

3.10.1.4 EmptyBorder

Die Klasse com.cisag.pgm.gui.EmptyBorder verhält sich ähnlich wie die Klasse LineBorder, nur das die „Linie“ zwar Platz benötigt aber ansonsten unsichtbar („transparent“) ist. Der damit erzielbare Effekt entspricht dem Setzen von Margins (siehe 3.1.1 VisualElement). Aus Gründen der Klarheit sollte zu diesem Zweck auch besser die Methode setMargins() benutzt werden.

3.10.2 Color

Die Klasse com.cisag.pgm.gui.Color dient zur Repräsentation von Farbwerten, z. B. wird die Vordergrund- bzw. Hintergrundfarbe von Elementen (siehe 3.1.1 VisualElement) durch Instanzen dieser Klasse repräsentiert.

Für Farben wird das RGB(A)-Farbmodell benutzt, d. h. jede Farbe wird aus vier Farbkomponenten zusammengesetzt. Die ersten drei Farbkomponenten entsprechen den drei Grundfarben rot (red), grün (green) und blau (blue). Die vierte Farbkomponente (A bzw. „alpha“) spezifiziert die „Undurchsichtigkeit“ bzw. Transparenz der Farbe. Der Wertebereich für jede der vier Komponenten liegt zwischen 0 und 255 (jeweils inklusive), wobei der Wert 255 für 100% steht.

Hinweis:
Transparente Farben werden in der aktuellen Version nicht unterstützt. Einzige Ausnahme ist Color.TRANSPARENT. Mithilfe von setBackground(Color.TRANSPARENT) lassen sich z. B. die Standardhintergrundfarben von Elemente so entfernen, dass bei dem Element die Hintergrundfarbe des Containers „durchscheint“.

Die Elemente besitzen bezüglich der Farben eine Voreinstellung, die von den aktuellen Benutzereinstellungen (Anzeigeeinstellungen/Thema) abhängig ist bzw. sich automatisch an diese anpasst. Das explizite Setzen von Farben ist daher nur zulässig, wenn es sich um Look & Feel unabhängige Grund- bzw. Signalfarben handelt. Zu diesen Farben zählen z. B. die Konstanten Color.BLACK, Color.WHITE, Color.RED, Color.GREEN, Color.BLUE und Color.TRANSPARENT.

Die Klasse com.cisag.pgm.gui.UIManager (siehe 3.10.6 UIManager) erlaubt den Zugriff auf die Look & Feel-abhängigen Farben.

3.10.3 Font

Die Klasse com.cisag.pgm.gui.Font dient zur Repräsentation von Schriftarten und Schrifteigenschaften. Über die Methode VisualElement#setFont(Font) (siehe 3.1.1 VisualElement) kann theoretisch jedem Element eine andere Schrift bzw. ein anderer Schriftstil oder eine andere Schriftgröße zugewiesen werden[43].

Hinweis:
Ähnlich wie bei den Farben, verwendet das UI-Framework auch bei den Schrifteinstellungen Look & Feel- bzw. benutzerabhängige Werte für die Elemente. Auch hier gilt, dass diese Voreinstellungen möglichst nicht durch feste (benutzerunabhängige) Werte übersteuert werden sollten.

Die Klasse com.cisag.pgm.gui.Font verfügt über zwei statische (Factory)-Methoden zur Erzeugung von Font-Objekten:

  • getFont(int style, int size)
  • getFont(String family, int style, int size)

Die zweite Methode sollte nicht verwendet werden, da die explizite Spezifikation einer Schriftart problematisch ist: Einerseits werden damit die Benutzereinstellungen übersteuert und anderseits kann nicht sichergestellt werden, dass der Client wirklich über die angegebene Schriftart verfügt.

Bei der ersten Methode sollte nach Möglichkeit als Schriftgröße immer der Wert Font.DEFAULT_SIZE spezifiziert werden. In diesem Fall bleibt der entsprechende Wert aus dem Look & Feel bzw. den Benutzereinstellungen erhalten.

Hinweis:
In Listen und Bäumen wird teilweise eine reduzierte Schriftgröße gefordert (siehe Semiramis-Styleguide). Zur Zeit bestehen leider nur zwei Möglichkeiten diese Forderung umzusetzen: Font.getFont(Font.PLAIN, 7) bzw. UIManager.getFont(“ListStyle.font_7pt”). Wenn möglich sollte die Variante mit dem UIManager gewählt werden, da es sich hier nur um einen Schlüssel, aber nicht um einen absoluten Wert handelt.

Für die Auswahl eines Schriftstils bzw. von Schriftattributen stehen folgende Konstanten zur Verfügung:

  • PLAIN
  • BOLD
  • ITALIC
  • UNDERLINE
  • STRIKETHROUGH
  • SUBSCRIPT
  • SUPERSCRIPT

Die Konstanten können i.d.R. miteinander (bitweise-OR) verknüpft werden. Die gleichzeitige Angabe von Font.SUBSCRIPT und Font.SUBSCRIPT ist nicht möglich. Ebenso kann Font.PLAIN nicht zusammen mit Font.BOLD oder Font.ITALIC genutzt werden.

3.10.4 Insets

Die Klasse com.cisag.pgm.gui.Insets dient der Spezifikation von Rahmen bzw. Randabständen in Elementen (siehe 2.1.2.3 Abstände, 3.1.1 VisualElement und 3.10.1 Border).

Randabstände lassen sich bei allen Elementen (com.cisag. pgm.gui.VisualElement) über die Methode setMargin(Insets i) setzen bzw. über die Methode getMargin() abfragen. Alle Elemente erhalten als Voreinstellung entsprechende Randabstände, die üblicherweise auch der jeweiligen Schriftgröße angepasst sind.

Zur Erzeugung eines Insets Objektes kann man den Konstruktor Insets(int top, int left, int bottom, int right) verwenden. Für jede der vier Seiten ist der gewünschte Abstand als Anzahl „Pixel“ zu übergeben.

Es wird jedoch empfohlen, zur Erzeugung von Insets die Klasse com.cisag.pgm.gui.UIManager zu benutzen (siehe 3.10.6 UIManager), da diese sowohl das aktuelle Look & Feel (Thema), die Schriftgröße und die Bildschirmauflösung berücksichtigt.

So liefert z. B. der folgende Code-Ausschnitt die Standard-Insets für Container (Views):

UIManager.getUIManager().getInsets(“Insets.all”, VisualElement.this)

Über die Angabe des Elements ist es dem UIManager möglich, elementspezifische Eigenschaften wie z. B. die Schriftgröße zu berücksichtigen. Der Parameter “Insets.all” dient als Schlüssel für die gewünschte Art von Insets (in diesem Fall: „an allen vier Seiten“). Entsprechende Schlüssel sind auch für andere Arten von Insets definiert.

3.10.5 Icon

Die Klasse com.cisag.pgm.gui.Icon dient der Repräsentation von Bildsymbolen bzw. Piktogrammen. Diese „Icons“ sind üblicherweise als Entwicklungsobjekt im Repository definiert und gespeichert. Die Anzeige von Icons erfolgt über entsprechende Elemente (Label, Button, IconField, etc.), die dazu notwendigen Informationen (Speicherort, Größe) werden über ein Objekt der Klasse com.cisag.pgm.gui.Icon bereitgestellt.

Typischerweise werden Instanzen von Icon über die statische Methode Icon.getIcon(String path) erzeugt. Diese bezieht alle Eigenschaften des Icons aus den Metadaten (Entwicklungsobjekt Icon). Bei Verwendung der statischen Methode Icon.getIcon(String path, int w, int h) kann die gespeicherte Größe im Repository übersteuert werden.

3.10.6 UIManager

Die Klasse com.cisag.pgm.gui.UIManager verwaltet alle Eigenschaften, die von dem jeweiligen Look & Feel, den Benutzereinstellungen, der Schriftgröße oder der Bildschirmauflösung abhängig sind. Hierzu zählen insbesondere Farben, Schriften, Icons, Rahmen und Abstände. Durch die zentrale Verwaltung wird gleichermaßen sichergestellt, dass die Oberfläche ein einheitliches Aussehen erhält und sich Änderungen („Face-liftings“) ebenfalls zentral durchführen lassen.

Der UIManager wird überwiegend von den Elementen selbst benutzt, über ihn beziehen sie ihre (benutzerabhängigen) Farben, Schriften, Icons usw. Der UIManager legt  z. B. fest, welche Farbe die Titelleiste im Shelf besitzt, welchen Rahmen ein Button benutzen soll, wie groß die Randabstände im Label sind oder welche Farbe die Selektion in der Tabelle haben soll.

Die von den Elementen (mithilfe des UIManagers) getroffenden Voreinstellungen sollten nicht geändert werden. Bei einer Änderung könnte sowohl die automatische Anpassung an die Benutzer- bzw. Clienteinstellungen als auch die Einheitlichkeit der Oberfläche leiden.

Falls es trotzdem notwendig sein sollte die Voreinstellungen zu ändern, dann sollte dazu der UIManager genutzt werden, d. h. statt mit festen Größen (RGB-Werte, Pixel), sollte immer mit indirekten Werten (Schlüsseln) gearbeitet werden.

Der UIManager stellt eine Art aktive Tabelle (Map) dar, in der die UI-Eigenschaften als Key/Value-Paare „gespeichert“ sind, wobei zur Abfrage folgende Methoden zur Verfügung stehen:

  • public Border getBorder(Object key)
  • public Color getColor(Object key)
  • public Font getFont(Object key)
  • public Icon getIcon(Object key)
  • public Insets getInsets(Object key)
  • public Insets getInsets(Object key, VisualElement elem)
  • public int getInt(Object key)

Als Schlüssel (key) wird immer ein String verwendet.

Die Instanz des für die Anwendung gültigen UIManagers bekommt man über die (statische) Methode getUIMana-ger().

3.10.6.1 Farben

Zur Unterstützung von benutzerspezifischen Farbschemas (Themes), verwendet das UI-Framework eine Palette mit logischen Farben. Zur Zeit umfasst diese Palette insgesamt 21 Einträge (15 Hauptfarben und 6 Sekundärfarben). Die Wahl eines Farbschemas durch den Benutzer führt dazu, dass diese 21 Einträge mit konkreten Farben belegt werden.

Der Zugriff auf die aktuellen Farben der Palette ist über die Schlüssel “primary1”, “primary2”, …, “primary15” und “secondary1”, “secondary2″, …,”secondary6” möglich. Also z. B. mit:

UIManager.getUIManager().getColor(“primary1”).

3.11 Steuerungskomponenten

3.11.1 Action, ActionListener

Typischerweise stellt eine Anwendung eine Reihe von Funktionen bereit, die durch den Benutzer direkt aufgerufen bzw. angestoßen werden können (z. B. „Laden“, „Speichern“, „Suchen“,…). In Semiramis werden diese Funktionen durch so genannte „Actions“ repräsentiert. Wobei den Actions dabei folgende Aufgaben zufallen:

  • Identifkation der Funktion (ID).
  • Bereitstellen von Informationen für die Visualisierung, insbesondere Texte (Label, ToolTip, Direkthilfe) und/oder Icons. Diese Daten werden typischerweise im Repository (Entwicklungsobjekt „Action“) erfasst.
  • Verwalten von (dynamischen) Zuständen. Über den Zustand „enabled“ wird z. B. signalisiert, dass die zugehörige Funktion „aufrufbereit“ ist, bzw. durch den Benutzer aufrufen werden darf.
  • Objekt an dem sich interessierte „ActionListener“ registrieren können (Event-Source).
  • Objekt an dem zusätzliche Informationen (Parameter) über ein eingetretenes Ereignis abgefragt werden können (Event-Objekt).

Weiterhin werden Actions dazu benutzt, um sich bei den Elementen für bestimmte Ereignisse zu registrieren (Doppelklick, Selektionsänderung, etc.)[44].

Ein Action Objekt erzeugt man z. B. mit dem Konstruktor: Action(int id, String abspath, ActionListener listener).

Der Parameter „id“ dient der spätereren Identifizierung der Action (erlaubt switch/case in der performAction()-Methode des ActionListeners), der Parameter „abspath“ spezifiziert ein Action-Objekt aus dem Repository und über den Parameter „listener“ kann bereits im Kontruktor ein ActionListener bei der Action registriert werden.

Hinweis:
Die selbst vergebenen IDs sollten in dem Bereich von 1 bis 999 liegen, damit es nicht zu Überschneidungen mit den Standard-IDs kommt.

Für Standard-Actions, wie z. B. Laden, Löschen, Speichern sind entsprechende IDs als Konstanten definiert (z. B. Action.LOAD, Action.DELETE, Action.UPDATE). Zusätzlich stehen für diese Standard-Actions auch verschiedene Factory-Methoden (z. B. getLoadAction() bzw. getLoad-Action(int id)) zur Verfügung.

Das Action Objekt verfügt über die Eigenschaften „allowed“ und „enabled“ sowie über eine Eigenschaft, die anzeigt, ob es sich um eine „Default-Action“ handelt. Diese Eigenschaften lassen sich über entsprechenden set/get-Methoden ändern bzw. abfragen.

Die Eigenschaften „enabled“ und „allowed“ sind miteinander verknüpft, d. h. eine Action ist nur dann enabled, wenn sie auch erlaubt (allowed == true) ist.

Das Verhalten bzw. die Interpretation von Default-Actions ist kontextabhängig. In Kontextmenüs werden Default-Actions z. B. nur als solche gekennzeichnet (durch Fettschrift hervorgehoben). In SmartButtons wird die Default-Action mit Hauptschaltfläche verknüpft.

3.11.2 ActionList

Die Klasse com.cisag.pgm.gui.ActionList bietet die Möglichkeit, mehrere Actions in einem Objekt zusammenzufassen. Ein solches ActionList-Objekt kann dann z. B. genutzt werden, um daraus einen MenuButton zu erzeugen.

[1]Für die Instanziierung werden die hinterlegten Metadaten im Repository  benötigt, welche über einen (absoluten) „Pfad“ spezifiziert werden müssen. Bei relativen Pfaden ergibt sich der absolute Pfad erst mit dem Hinzufügen zu einem Container.

[2]Bei Implementierung eigener Subklassen ist darauf zu achten, dass bei den Elternklassen die Referenzen auf X-Element initialisiert wird (siehe Methode setUiElement())

 

[3]Genauere Angaben sind bei der jeweiligen Subklasse nachzulesen.

[4]siehe Programmierhandbuch: dataFromUI()/dataToUI()

[5]Auch bei einem leerem Feld liefern die meisten Felder einen von „null“ unterschiedlichen Wert (z. B.: Leerstring oder „0“)

 

[6]Vorausgesetzt, dass sich das übergeordnete Fenster nicht geändert hat.

 

[7]Einige nicht-Container Elemente, z. B. Tree, List, Table, besitzen diese Fähigkeit auf Elementebene.

[8]Bei dem Element handelt es sich im Allgemeinen um einen Container (z. B. View) mit Subelementen.

[9]Gemeinsame bzw. getrennte Speicherung der Zeitzoneninformation für die Attribute eines BOs

[10]Der gespeicherte Wert ist um 24 Stunden größer als der im Feld angezeigte Wert.

 

[11]com.cisag.pgm.dialog.DataDescription

 

[12]Die in java.util.Date gespeicherte Datums- und Zeitinformation ist grundsätzlich auf UTC (GMT) normiert.

[13]Wird in künftigen Versionen nicht mehr unterstützt werden.

[14]Nur Listen.

 

[15]Nur Listen.

 

[16]Das (versehentliche) Laden von hunderttausenden von Datensätzen würde einen Application-Server möglicherweise zusammenbrechen lassen oder mindestens zu völlig inakzeptablen Antwortzeiten führen.

 

[17]Solange die Eigenschaft allRowsLoaded den Wert false hat, wird im PageButton ein „+“ angezeigt.

 

[18]Falls sich nicht genügend Datensätze in dem Modell befinden, wird automatisch eine „Action“ ausgelöst, die es erlaubt weitere Datensätze zu laden und dem Modell hinzuzufügen.

 

[19]Voraussetzung ist, dass alle Zeilen exakt dieselbe Höhe haben, anderenfalls ist das Verhalten beim Blättern undefiniert.

 

[20]Auf dem Client kann diese Datei entweder gespeichert oder direkt mit einer Anwendung (z.B. Microsoft Excel) geöffnet werden.

 

[21]Die GUID ist auch wichtig, damit dem Feld bzw. der „Spalte“ eine Berechtigung zugewiesen werden kann.

 

[22]Die Seitengröße sollte möglichst dynamisch an den effektiv zur Verfügung stehenden Platz angepasst werden.

 

[23]Die Methode fügt die MetaCheckBox dabei automatisch in den Header ein.

 

[24]Hier ist entscheidend, der im Konstruktor übergebene Wert für den Parameter „editable“, nicht der mit setEditable() gesetzte Wert.

 

[25]Das sollte unmittelbar nach dem Aufruf des Konstruktors erfolgen

 

[26]Über die Methode setRowHeaderVisible() kann die Sichtbarkeit der Zeilenüberschriften beeinflusst werden.

 

[27]Die anderen Konstruktoren werden in Semiramis-Anwendungen nicht mehr benutzt und sind als „deprecated“ anzusehen. Sie werden in einem der folgenden Releases entfernt.

 

[28]Die Seitengröße sollte, wie bei der Liste, dynamisch an den effektiv zur Verfügung stehenden Platz angepasst werden.

 

[29]Die Editibarkeit von einzelnen Zeilen oder Zellen lässt sich unabhängig über die Instanzen von CisListPartMutable bzw. die Spaltendefinitionen festlegen.

 

[30]Die Klasse com.cisag.pgm.gui.Field definiert mit createTableEditor() eine entsprechende Methode zum Erzeugen solcher Editoren.

 

[31]Die Daten für dieses Feld werden automatisch aus der Eigenschaft „rowHeaderValue“ des Datensatzes (CisListPartMutable) übernommen.

 

[32]Über die Methode setPageButtonVisible() kann der PageButton bei Bedarf ausgeblendet werden.

 

[33]Der übergebene HTML-Text wird nicht geprüft. Fehler können (je nach Client) auch Auswirkungen auf die gesamte Oberfläche haben.

 

[34]Wenn innerhalb einer Sitzung mit „https“-Protokoll andere Seiten mit „http“-Protokoll geladen werden sollen, kommt es zu einer entsprechenden Warnmeldung des Browsers.

 

[35]Das ist manchmal unerwünscht, da diese Eigenschaft von dem Container übernommen wird, aber es entspricht dem Verhalten von Swing. Bei Bedarf kann es durch den direkten Aufruf von setMaximumWidth/-Height angepasst werden.

 

[36]Die definierten Führungslinien werden auch auf die ListViews vererbt.

 

[37]Die nicht-leeren Konstruktoren von StandardLayout sollten nicht mehr verwendet werden.

 

[38]Die anderen Konstruktoren würden neue Führungslinien definieren.

 

[39]Als Vereinfachung wird hier angenommen, dass der Container werder Border noch Margins hat und das bei dem BorderLayout keine Werte für hgap bzw. vgap gesetzt sind. Falls vorhanden, würden diese Werte entsprechend berücksichtigt, z. B. von der verfügbaren Breite bzw. Höhe des Containers abgezogen.

 

[40]Welches Element „oben“ liegt wird durch die Reihenfolge im Container (Index) bestimmt.

 

[41]Im Grunde kann hier jeder Wert zwischen 0.0f und 1.0f benutzt werden. Die Konstanten VisualEment.TOP (0.0f), VisualElement.CENTER (0.5f) und VisualEment.TOP (1.0f) stellen lediglich die häufigsten Anwendungsfälle dar.

 

[42]Bei Bedarf sollte die Klasse DecoratedBorder verwendet werden, diese dient als Nachfolger der aufgeführten Klassen und unterstützt die entsprechenden Stile weiterhin.

 

[43]Die Eigenschaft „font“ wird über die Container-Hierarchie vererbt, d. h. das Setzen eines Fonts bei jedem Element ist nicht notwendig und auch nicht zu empfehlen.

 

[44]Die Registrierung einer Action erlaubt, gegenüber der direkten Registrierung eines ActionListeners, die eigene Vergabe von Action-IDs und somit eine einfachere (zentrale) Ereignisbehandlung.

 

Czy ten artykuł był pomocny?