Lade...
 

ObjectListView, OListView

ObjectListView, OListView, OLView

ObjectListView(name~aliasName, flags, x, y, w, h)

Parameter
Parameter   Beschreibung
name * Identifikator oder KLASSE::ausdr
aliasName   ein zusätzlicher Identifikator
flags   Flags
x * Position X (in Minicells)
y * Position Y (in Minicells)
w * Breite (in Minicells)
h * Höhe (in Minicells)
  • - Pflichtparameter

Das Tupel (Klasse, Zugriffsausdruck) definiert eine Abbildung auf Modelldaten (siehe FillWindow, DrainWindow). Wie mit jeder ObjektBox können auch mit dieser Relationen zwischen Objekten dargestellt und interaktiv bearbeitet werden.

Eine ObjectListView ist in Funktionalität und Aussehen der ObjectList ähnlich. Während die ObjectList eine Collection als Liste (Listbox) darstellt, wie sie in jeder Windows-Version (und entsprechend auf anderen Plattformen) vorhanden war, nutzt die ObjectListView die modernere und weiter variierbare ListView-Box, wie sie mit Windows 95 im Datei-Explorer eingeführt wurde.

Asynchronität

Ein weiterer wichtiger Unterschied zu anderen ObjectBoxen ist, dass die ListView die Spaltenformate der darzustellenden Zeilen erst dann (asynchron) auswertet, wenn diese Zeilen sichtbar sind. Das heißt, dass einige Formate erst beim Scrollen ausgewertet werden. Dies hat natürlich auch zur Folge, dass der InstantView-Zustand (wie z.B der Plug-Space oder Währungstabellen) während der Ausführung von FillObox zu dem Auswertungszeitpunkt potenziell nicht mehr angemeldet sind und womöglich auch die Transaktion bereits geschlossen wurde und die Formate in einer eigenen Transaktion ausgewertet werden. Falls dieses Verhalten zu unerwünschten Nebenwirkungen führt, kann die synchrone Auswertung per RetrieveData erzwungen werden.

 

Achtung!
Ist eine Liste nur eine Zeile hoch, und ist diese Zeile kleiner als ein Standardzeichen der ausgewählten Schriftart, so wird die Zeilenhöhe auf 2 Pixel verkleinert, womit der Eintrag kaum erkennbar ist.

Beispiel zur Verdeutlichung (Achten Sie auf die Höhe, die ganz am Ende der Zeile angegeben ist):
Bringt keinen sichtbaren Eintrag bei FillWindow, weil die Liste nicht hoch genug ist:

 ObjectListView(CX_TRANSACTION::monitors, NO_COLUMNHEADER, AUTO_POSITION, NO_DRAIN, BITMAP_SIZE, ENTIRE, 350, 33, 230, 9)

So passt dann die Schriftart in die Liste und die Zeile wird angezeigt:

 ObjectListView(CX_TRANSACTION::monitors, NO_COLUMNHEADER, AUTO_POSITION, NO_DRAIN, BITMAP_SIZE, ENTIRE, 350, 33, 230, 10)

 

Für das Layouting der ListView in MorphIT gibt es eine zusätzliche Sonderregel.
Sollte die ListView per vertikalem STRETCH an die enthaltende Gruppe attached sein, dann zeichnet sich die ListView immer mindestens so hoch, dass alle Einträge ohne Scrolling darin angezeigt werden können.
Die Höhe der Gruppe richtet sich dann nach der Höhe der ListView (angegebene Gruppenhöhe wird ignoriert) und die in der ListView angegebene Höhe wird als Mindeshöhe der ListView interpretiert.

 

Es gibt typische Muster, wie die Daten in einer ListView formatiert werden.

Header:
Diese bietet auch eine integrierte Darstellung von Spaltenköpfen, die auch über die InstantView® Schnittstelle über das (Pseudo-) Widget Header angesteuert werden kann.
Um sie zu nutzen, wird dem Header-Widget (siehe Hilfetext-Header) der Identifikator der ObjectListView als Parameter übergeben. Die Prompts und Buttons als untergeordneten Widgets des Headers werden dann in den integrierten Header der ObjectListView kopiert (die Originale sollten via HIDDEN-Flag unsichtbar gemacht werden), dabei stellen Buttons immer Spalten-Header dar, durch die durch betätigen die jeweilige Spalte sortiert werden kann.
Mehrfaches betätigen eines Sortier-Spalten-Headers dreht die Sortierorientierung um bzw. hebt sie auf. Wird ein Spalten-Header mit gedrückt gehaltener -Taste betätigt, wird die jeweilige Spalte zu der bisherigen Sortierung zugefügt, und bildet damit eine Mehrfachsortierung.
Die Sortierung wird visualisiert (Pfeile). Zweite, Dritte usw. Sortierkriterien werden entsprechend mit zwei, drei usw. Pfeilen gekennzeichnet. Eine mit SetSort festgelegte Sortierung wird in exakt gleicher Weise visualisiert. Wird eine Sortierung zwar gesetzt (mit SetSort) aber nicht aktiviert (nicht Sort aufgerufen), wird sie durch deaktivierte (graue) Pfeile dargestellt. Ein solche deaktivierte Sortierung kann durch drücken mit gehaltener -Taste auf  einen Spalten-Header, der zur Sortierung gehört, aktiviert werden. Unter bestimmten Bedingungen (bereits aktivierte Sortierung wird erneut (identisch) mit SetSort gesetzt, Liste enthält nicht mehr als ein Element) erkennt die ObjectListView, dass die Sortierung aktiv ist, obwohl Sort nicht explizit aufgerufen worden ist.
Unabhängig von der Sortierung wird beim Betätigen der Spalten-Header zunächst die SELECT-Sektionen der korrespondierenden Widgets im (InstantView®-)Header aufgerufen. Wurde eine ObjectListView aus einer ObjectList adaptiert, ist darauf zu achten, dass eventuell vorhandene Sortiermechanismen in diesen SELECT-Reaktionen auszukommentieren sind. Erfolgt der Aufruf von cancel in (besser gesagt am Ende) der SELECT-Implementation, unterbleibt die automatische Sortierung. Ein SELECT an einem Header-Button ausschließlich mit der Anweisung cancel ist also eine Implementation eines integrierten Spalten-Headers der nicht sortiert.
Spalten können durch Drag und Drop auf den Spalten-Headern umsortiert werden. (Dieses Drag und Drop ist nicht mit dem InstantView®-Drag und Drop   zu verwechseln. Es werden keinerlei Eingriffsmöglichkeiten, etwa Messages unterstützt.) Dabei behält jede Spalte ihre ursprüngliche Formatlistennummer. Ein SetSort mit dieser Nummer sortiert also immer die selbe Spalte, ganz gleich in wie weit die Spalten umsortiert werden.

Erreicht der Maus-Cursor den Bereich zwischen 2 Spalten-Header (Spalte) wandelt er sich in ein senkrechte Linie mit 2 waagerechten Pfeilen. Wenn dies geschieht kann man die Breite des Spalten-Headers links neben dem Cursor ändern, in dem man den Cursor bei gedrückter linker Maustaste nach links oder rechts bewegt. Klickt man hingegen in dieser Position doppelt, wird unabhängig vom Flag AUTO_POSITION (s.u.) die linke Spalte genau so breit gemacht, dass alle Spalten-Elemente genau in diese passen, also so breit wie das breiteste Spalten-Element.
Mit diesem Doppelklick bzw. dem Ziehen der Spaltenbreite wird bei AUTO_POSITION die automatische Berechnung der Spaltenbreite der betroffenen Spalte ein- bzw. ausgeschaltet.

 

Formatierung, Darstellung und Interaktion:
Während in der ObjectList Spalten-Elemente mit der selben Spaltennummer (über COLUMN-Flag in SetFormat gesetzt) einfach übereinander dargestellt werden, werden in der ObjectListView alle diese Spalten-Elemente zusammengefügt (gemerged). Dabei werden zunächst die enthaltenen Bitmaps gefiltert und das erste (nach Formatlist) von ihnen vor dem Text am linken Rand der Spaltenzelle dargestellt. Alle weiteren Bitmaps verfallen. Die Texteinträge werden ihrer Reihenfolge nach zu einem String (mit ' ' () getrennt) zusammengefasst und rechts dargestellt. Über Links- und Rechtsbündigkeit entscheidet das erste Format.

Als reines Basis-Windowobjekt, folgt die zugrundegelegte ListView-Box den allgemeinen Eigenschaften der Windowsoberfläche. Dadurch ist insbesondere die Markierung der Elemente per Anklicken grundsätzlich anders als in der ObjectList: mit - und  -Taste können ganze Bereiche ausgewählt werden. Ohne jedwelche Taste, führt ein Anklicken eines Elementes immer zunächst zur Aufhebung aller bestehenden Selektionen und danach zur Selektion des unter dem Maus-Cursor befindlichen Elementes.

Ist die ObjectListView (aktiv) sortiert, kann in der ersten Spalte des Sortierkriterium über drücken von Buchstaben-Tasten navigiert werden. Hierbei werden kurz nacheinander eingetippte Buchstaben als (Teil-)String aufgefasst und nach diesem in der Spalte gesucht. Hierbei werden intern die Spalten-Elemente ebenfalls in Strings umgewandelt. Ein Versuch ein Element durch teilweise Eingabe dieses Textes schlägt fehl, wenn die Spalte zwar sortiert ist, ein Einträge in den Spalten-Elementen jedoch als String aufgefasst nicht sortiert sind.
Ein Beispiel hierfür ist eine Spalte mit Datumsfeldern: die Daten "3.8.99","12.9.99" sind in dieser Reihenfolge nach Datum sortiert, als reine (uninterpretierte) Strings, müsste '1' jedoch vor '3' stehen, wären sie also nicht sortiert. Wenn eine Buchstaben-Navigation fehl schlägt wird ein Element angesteuert, dass eventuell nichts mit dem eingegebenen Text zu tun hat. Es erfolgt keine Fehlermeldung.
Rechtsbündigkeit wird berücksichtigt und führt auch bei Mischung mit Linksbündigkeit allein nicht zum Fehlverhalten.

Bitmaps, die in einem ObjectListView angezeigt werden sollen, dürfen maximal 256 Farben besitzen und müssen eine Palette haben. Dies lässt sich mit den Grafikformaten .PNG, .BMP, .GIF und .TIF realisieren.

 

virtuelle Liste:
Neben der reinen Darstellung unterscheidet sich die ObjectListView in der Art, wie sie die darzustellenden Daten einliest und verarbeitet. Dadurch ist es möglich, in ihr sehr große Datenmengen in relativ kurzer Zeit sichtbar und zugreifbar zu machen. Hierfür nutzt sie ein Feature der ListView-Box, die sogenannte Virtual List:
Während die Listbox in der ObjectList zu Beginn (nach dem Initialize) sämtliche Daten einließt, komplett in ihre visuelle Repräsentanz wandelt und in dieser speichert, versucht die ObjectListView, diesen Aufwand möglichst gering zu halten. Hierfür werden aus der Quelle (z.B. Zugriffsausdruck auf ein Collection) zunächst nur die Referenzen auf die betroffenen Objekte in einer internen Tabelle gespeichert. Erst wenn von der Oberfläche bestimmte Bereiche der Liste zur Darstellung angefordert werden, werden für die betroffenen Objekte die visuellen Repräsentanzen erstellt und an die Oberfläche zurück gemeldet.
Damit sind die visuellen Repräsentanzen zur Laufzeit natürlich nicht (für alle) Objekte verfügbar, bzw. werden in zunächst nicht vorhersehbarer Reihenfolge, unabhängig von der Einlesereihenfolge der Objekt-Referenzen, überhaupt erst erstellt. (Einmal erstellte visuellen Repräsentanzen werden zur Zeitersparnis zwischengespeichert und nur unter bestimmten Voraussetzungen erneut erstellt.) Dies hat mehrere Implikationen im Umgang mit der ObjectListView:

  • Die Sortierung (z.B. bei FillObox und Sort) erfolgt über die Objekte direkt, d.h. , sofern möglich, über einen Zugriffsausdruck. Nur wenn Sortierattribute über Push-Statements (siehe SetFormat) angegeben werden,  oder über den Index der Formatliste (Nummer der SetFormat-Anweisung; siehe SetSort) sortiert wird, muss die ObjectListView hierfür eigens für sämtliche Objekte visuelle Repräsentanzen erstellen.
    Deswegen erzielt man beim Sortieren (genau umgekehrt zum Verhalten der ObjectList) die beste Performance, wenn nach Möglichkeit immer über Zugriffsausdrücke und nicht über Formatlistenindizes sortiert wird. Beim drücken der integrierten Header (s.o.) wird übrigens immer versucht ein Zugriffsausdruck zur betroffenen Spalte zu generieren, und entsprechend über diesen zu sortieren.
  • Bei der Implementation von (non-primitive) Push-Statements ist darauf zu achten, dass ihr Ergebnis ausschließlich vom Zustand des jeweiligen Objektes abhängt, und somit autonom von jedwelchen Systemzuständen ist. Ein Mitlaufenlassen einer Aufrufnummer für jedes Call des Statements etwa muss fehlschlagen.

 

DrainWindow:
Während bei FillWindow nur die Objekte angefasst werden, die auf dem Bildschirm angezeigt werden, werden bei DrainWindow alle Objekte angefasst. Bei vielen Objekten kann dieser Vorgang einige Zeit dauern. Daher gilt: Bei ListViews, die viele Objekte aufnehmen könnten (weil der Anwendungsfall dies erfordert oder zulässt), sollte DrainWindow nicht benutzt werden. ListViews, die nur wenige Objekte anzeigen werden, können per DrainWindow ausgelesen werden.

Die Objektbox wird mit folgenden Anweisungen programmiert (sind identisch mit den Anweisungen für die ObjectList):

Der Befehl Widget legt eine ObjectListView auf den Stack, so dass auf die Methoden und Attribute eines Widgets zugegriffen werden kann.

Folgende Methoden werden von der ObjectListView angeboten:

 

Flags
Flag Beschreibung
ACCEPT_DROP Auf der Objektbox können von einer anderen Objektbox mit Drag-and-Drop über den Bildschirm gezogene Objekte abgelegt werden. Was mit den Objekten geschehen soll, muss in der Aktionsliste beschrieben werden (siehe Beispiel)..
AUTO_POSITION Die X-Positionen werden automatisch berechnet, müssen also mit SetFormat nicht explizit vorgegeben werden. Anders als in der ObjectList sind nur für die gerade sichtbaren Objekte sicher Visualisierungen vorhanden. Deswegen ermittelt AUTO_POSITION nur über diesen Bereich den Spalten-Eintrag mit dem längsten Text. (plus Bitmapbreite plus Breite Abstand Bitmap/Text, falls eine Bitmap angezeigt wird.) Dies führt zu dem unschönen Effekt, dass sich beim Scrollen die Spaltenbreiten ständig ändern. Um dies zu vermeiden, muss die Spaltenbreite nach AUTO_POSITION eingefroren werden.
CONTEXTMENU(identifikator) Der Identifikator ist ein Bezeichner eines Items innerhalb einer Menu- oder ContextMenuList-Deklaration. Das unter diesem Item hängende Untermenu wird automatisch beim betätigen der rechten Maustaste eingeblendet. Wird daraufhin ein Menupunkt ausgewählt wird wie zu Item beschrieben die jeweilige Aktion gestartet, in gleicher Weise, als wäre der Menueintrag aus dem Hauptmenu heraus aufgerufen worden.
Zusätzlich kann man jedoch bei Ausführung von SELECT zu dem entsprechenden Item mittels GetCurrentWidget ermitteln aus welchem Windowobjekt heraus der Menupunkt via ContextMenu aufgerufen wurde. Bei einem Ausruf aus dem Hauptmenu liefert GetCurrentWidget NULL zurück.

Soll ein ContextMenu nicht automatisch erscheinen, so kann es (nach Gestaltungsrichtlinie sollte dies als Reaktion auf die rechte Maustaste, also innerhalb MOUSE_CLICK_R erfolgen) mittels PopupMenu auch aus InstantView® heraus aufgerufen werden. In diesem Fall sollte auf die Angabe des Flags CONTEXTMENU verzichtet werden, da sonst das Menu zweimal (einmal automatisch, einmal gesteuert) erscheint.

GRIDMENU(identifikator) Setzt das Gridmenü fest. Der Identifikator ist ein Bezeichner eines Items innerhalb einer Menu- oder ContextMenuList-Deklaration.
DRAG_COPY Die gerade ausgewählten Objekte können mit der rechten Maustaste zu einer anderen Objektbox oder zu einem Window gezogen werden (Drag-and-Drop). Die Objekte können nur auf einem Ziel mit Flag ACCEPT_DROP abgelegt werden. Die Listboxeinträge bleiben erhalten.
DRAG_MOVE Wie bei DRAG_COPY können die gerade ausgewählten Objekte zu einer anderen Objektbox oder zu einem Window gezogen werden. Die entsprechenden Listboxeinträge werden gelöscht, wenn die Objekte auf einer anderen Listbox oder einem Window mit Flag ACCEPT_DROP abgelegt wurden.
HELP(anchor) Help("file#anchor") verbindet das Windowobjekt mit Online-Hilfe im HTML-Format. Wenn kein Filename angegeben wurde, gilt die im Modul festgelegte HTML-Datei.
HIDDEN Die Objektbox bleibt solange unsichtbar, bis Anweisung Show sie auf dem Bildschirm erschienen lässt.
HZ_SCROLL_BAR Die Objektbox erhält zusätzlich zum vertikalen auch einen horizontalen Scrollbar.
ITEM(w, h), ITEM(w), ITEM(, h) Wenn Breite und Höhe eines Listboxeintrags von den durch die Größe der Listbox vorgegebenen Maßen abweichen, werden sie auf diese Weise angegeben. Eine größere Breite ist zusammen mit Flag HZ_SCROLL_BAR sinnvoll. Mehrzeilige Einträge benötigen eine explizite Höhenangabe.
LIST_INVALID (ab 4.2) Normalerweise werden in eine Objektbox nur gültige Objekte aufgenommen. Wenn dieses Flag gesetzt ist, werden jedoch auch ungültige Objekte aufgenommen und angezeigt.
LIST_ORIGIN Wird ein ungültiges Objekt in eine ListView eingefügt und es gibt ein gültiges Austauschobjekt, wird normalerweise das gültige Austauschobjekt aufgenommen. Dieses Flag verhindert das, so dass nur das gültige Originalobjekt aufgenommen wird. Weiter unten wird das Zusammenspiel mit LIST_INVALID genauer erläutert.
MIN_HEIGHT(h) Höhe der Liste fällt in keinem Falle unter den Wert h (Angabe in Minicells). Dies ist vor allem in Kombination mit Attachments von Nutzen.
MIN_WIDTH(w) Breite der Liste fällt in keinem Falle unter den Wert w (Angabe in Minicells). Dies ist vor allem in Kombination mit Attachments von Nutzen.
NO_COLUMNHEADER Es werden keine Spaltenbeschreibungen angezeigt.
NO_FORMAT_FILTER 194900 Es werden Objekte, welche aufgrund des spezifizierten Formates nicht angezeigt werden können, nicht aussortiert.
NO_SORTHEADER Die Spaltenköpfe werden nicht als Knöpfe dargestellt, deshalb ist die Liste auch nicht per Knopfdruck auf einen Spaltenkopf sortierbar. Man kann aber noch die Spaltenbreite ändern und auch Spalten verschieben.
OPTIMIZE Die Optimierung bezieht sich auf die Zugriffsausdrücke für die Spalten der List (vergleiche Anweisung SetFormat): Gleiche Teilausdrücke werden nur einmal ausgewertet (weitere Hinweise ...).
SELECT_MULTIPLE Es ist möglich, mehrere Objekte gleichzeitig zu selektieren (nur für Listbox!).
TOOLTIP(mlString) Der angegebene String wird als Hinweistext (Tooltip) eingeblendet, oder, falls ein Event TOOLTIP ebenfalls definiert ist, an diesen übergeben. Das Erscheinen des Tooltips wird vom System automatisch nach eine bestimmten Zeit des Verharrens des Maus-Cursors über dem Windowobjekt ausgelöst. Der String kann mehrsprachig sein. An das Event wird der jeweils zur eingestellten Sprache aktuelle übergeben.

Transaktionsabbruch

Bei einem Transaktionsabbruch (AbortTXN, Attention(AbortTXN), usw.) wird die ListView geleert - aber nur dann, wenn sie innerhalb der Transaktion verändert wurde. Dadurch wird sichergestellt, dass die ListView keine Objekte enthält, die es möglicherweise nicht mehr gibt (z.B. neue persistente Objekte, die durch den Transaktionsabbruch wieder gelöscht werden).

Zusammenspiel LIST_INVALID mit LIST_ORIGIN

Ohne Flags werden nur gültige Objekte aufgenommen, bei ungültigen Objekte das gültige Austauschobjekt. LIST_INVALID erlaubt es, auch ungültige Objekt aufzunehmen, LIST_ORIGIN nimmt nur das Originalobjekt auf, nicht das Austauschobjekt:

Flags / Objekt g ug u
- g g -
LIST_INVALID g g u
LIST_ORIGIN g - -
LIST_INVALID+LIST_ORIGIN g u u

g = gültiges Objekt,
ug = ungültiges Objekt mit gültigem Austauschobjekt,
u = ungültiges Objekt

Achtung!
Bei der Kombination LIST_INVALID mit LIST_ORIGIN wird auch bei einem gültigen Austauschobjekt immer das Originalobjekt in die Liste aufgenommen. Dieses wird z.B. bei einem Doppelklick oder bei dem Befehl GetObject auf den Stack gelegt, d.h. es liegt möglicherweise ein ungültiges Objekt auf dem Stack, zu dem es ein gültiges Austauschobjekt gibt - das ist in ClassiX® unüblich! Wenn mit dem gültigen Austauschobjekt gearbeitet werden soll, ist ein "this." voranzustellen, z.B. "this.uniqueID".

Schnelle Liste

Durch Kombination von LIST_INVALID, LIST_ORIGIN und NO_FORMAT_FILTER werden alle prüfenden Routinen, welche Datenverkehr verursachen, deaktiviert. Wird zusätzlich auf eine Sortierung verzichtet, oder diese in begrenztem Umfang verwendet, wird die Liste um ein Vielfaches schneller angezeigt, da weniger Daten übertragen werden müssen. Dabei hängt es allerdings vom Anwendungsfall ab, ob zum Beispiel eine Liste ohne Sortierung, oder eine Liste ohne gültige Austauschobjekte, für den Nutzer hilfreich ist.