Rich-UI-Widget 'DataGrid' und 'DataGridTooltip'

Ein Rich-UI-Widget 'DataGrid' (Datenraster) definiert eine Feldgruppe von Zeilenwerten in einer Tabelle. Dieser Abschnitt enthält zunächst allgemeine Informationen über das Widget und stellt anschließend detaillierte Referenzinformationen zur Verfügung.

Einführung

Das Verständnis des Datenrasters (Datagrid) setzt voraus, dass Sie mit den folgenden Themen vertraut sind:
  • Definition von Spaltenüberschriften und Datenzeilen.
  • Definition eines Verhaltens, wobei es sich um eine Eigenschaft handelt, die eine Feldgruppe mit Funktionen enthält. Die Funktionen für ein bestimmtes Verhalten werden bei der Wiedergabe des Rasters in der Reihenfolge der Feldgruppenelemente ausgeführt.
  • Definition eines Listeners, bei dem es sich ebenfalls um eine Eigenschaft handelt, die eine Feldgruppe mit Funktionen enthält. Die Funktionen für einen bestimmten Listener werden in der Reihenfolge der Feldgruppenelemente als Reaktion auf eine Benutzeraktion wie einen Klick oder, in einigen Fällen, als Reaktion auf einen Funktionsaufruf ausgeführt, der eine Zeile aus- oder abwählt oder ein Kontrollkästchen aktualisiert.
  • Anpassung eines Mechanismus für die Sortierung des Rasters nach einer Spalte.
Verhalten und Listener können sich auf die Darstellungsmerkmale auswirken und verschiedene Arten von Logik aufrufen. Sie können zum Beispiel eine Sortierung nach einer Spalte veranlassen, auf einen Service zugreifen, einen Wert berechnen und diesen in einer Rasterspalte anordnen oder ein Widget konfigurieren und dieses in einer Rasterspalte platzieren. Sie können auf diese Grundlagen auf verschiedene Weisen aufbauen, wie zum Beispiel:
  1. Sie können auf eine Benutzer-ID in einer Spalte des Datenrasters zugreifen.
  2. Sie können diese ID in einem REST-Serviceaufruf verwenden, der eine Fotografie an eine Rückruffunktion zurückgibt.
  3. Sie können diese Fotografie in ein Bildwidget ('Image') einbetten, das im Handler global definiert ist.
  4. Sie können dieses Widget in derselben Zeile wie die Benutzer-ID in einer Datenrasterspalte platzieren.
Das folgende Beispiel veranschaulicht einen einfacheren Einstieg:
  1. Definieren Sie einen Datensatzabschnitt ('Record') als Basis einer Feldgruppe von Datensätzen. Jeder Datensatz enthält eine Gruppe von Werten, die in einer Zeile eines Datenrasters angezeigt werden sollen.

    Der Datensatzabschnitt sieht wie folgt aus:

    Record Stock type BasicRecord
       Symbol STRING;
       NumShares INT;
       Quote  DECIMAL(5,2);
       SelectQuote Boolean;
    end

    Die Feldnamen sind wichtig, da auf sie später in der Deklaration der Rasterspalten verwiesen wird.

  2. Deklarieren Sie die Feldgruppe von Datensätzen wie im folgenden Beispiel:
    stockList Stock[] = [
       new Stock{SelectQuote = false, Symbol = "Company1", Quote = 100.00, NumShares = 40 },
       new Stock{SelectQuote = false, Symbol = "Company2", Quote = 200.00, NumShares = 10 } ]; 

    Die Reihenfolge der Felder in einem bestimmten Datensatz ist nicht von Bedeutung. Allerdings ist die Reihenfolge der Datensätze in der Feldgruppe standardmäßig die Reihenfolge der Zeilen im Datenraster.

  3. Deklarieren Sie das Datenraster an einer Position, die auf die vorherige Datensatzdeklaration folgt. Das folgende Beispiel zeigt ein solches Datenraster:
    myGrid DataGrid{...};
    Die Deklaration enthält in der Regel die Eigenschaften columns und data:
    • Ordnen Sie für die Eigenschaft columns eine Feldgruppe von Datensätzen vom Typ 'DataGridColumn' zu.
      Für das vorliegende Beispiel wird die folgende Einstellung verwendet:
      columns = [
         new DataGridColumn { name = "Symbol", displayName = "Company Symbol"},
         new DataGridColumn { name = "Quote", displayName = "Price Per Share" },
         new DataGridColumn { name = "NumShares", displayName = "Number of Shares" },
         new DataGridColumn { name = "Total", 
                              displayName = "Value of Shares",
                              formatters = [totalFormatter] }
      ]

      Jede der ersten drei Deklarationen vom Typ 'DataGridColumn' verweist auf ein Datensatzfeld in der Datensatzfeldgruppe Stock. Die vierte Deklaration gibt eine berechnete Spalte an. Dies ist eine Spalte, zu der kein entsprechendes Datensatzfeld vorhanden ist. In diesem Fall ist dies das Feld ohne Datensatz mit dem Namen Total.

      Die Reihenfolge der DataGridColumn-Elemente legt die Reihenfolge fest, in der die Spalten angezeigt werden.

    • Ordnen Sie für die Eigenschaft data die Datensatzfeldgruppe vom Typ Stock zu. Das folgende Beispiel zeigt eine solche Einstellung:
      data = stockList as any[]

      Jedes Element der Feldgruppe stellt eine Untergruppe der Daten bereit, die für eine Zeile im Datenraster erforderlich sind.

    In den meisten Fällen erfordert Rich-UI, dass Sie Variablen deklarieren, bevor Sie auf sie verweisen. In diesem Beispiel muss stockList vor dem Datenraster deklariert werden.

Sie legen Verhalten und Listener fest, indem Sie Eigenschaften Werte zuordnen. Jede dieser Eigenschaften gehört zu einem Stellvertretertyp ('Delegate'), der die Parameterliste und den Rückgabewert angibt, die für beliebige der Funktionen erforderlich sind, die der Eigenschaft zugeordnet sind. Im Beispiel wird die DataGridColumn-Eigenschaft formatters für die vierte Spalte festgelegt. Diese bewirkt den Aufruf einer Funktion, die drei Parameter empfängt und keinen Rückgabewert hat. Die Funktion sieht wie folgt aus:
function totalFormatter(class String inout, value String inout, rowData any in)

   // Gesamtwert der Aktien (Shares) anzeigen, nachdem der Wert aus dem Inhalt von
   //    zwei anderen Spalten in derselben Zeile berechnet wurde
   value = rowData.NumShares as INT * rowData.Quote as DECIMAL(5,2);
end

Der Aufruf einer Funktion, auf die in der Eigenschaft formatters verwiesen wird, erfolgt einmal pro Zeile, bevor das Raster wiedergegeben wird. Der Inhalt der gesamten Zeile ist im dritten Parameter verfügbar. Sie können die spaltenspezifische Zelle aktualisieren, indem Sie entweder den ersten Parameter festlegen, durch den die CSS-Klasse gesteuert wird, oder den zweiten Parameter festlegen, durch den der Wert gesteuert wird.

Vorsicht:
Wenn Sie eine Verhaltensfunktion schreiben, vermeiden Sie eine erneute Wiedergabe des Rasters, sei es durch Aufrufen der widgetspezifischen Wiedergabefunktion oder sei es durch Festlegen einer Datenraster- oder Datenspalteneigenschaft. Eine erneute Wiedergabe hat eine lange Verzögerung oder in vielen Fällen eine Laufzeitbeendigung zur Folge.

Führen Sie eine erneute Wiedergabe des Rasters nur in einer onConstruction-Funktion, in einem Listener oder in einem anderen Ereignishandler aus, wie zum Beispiel einem Handler, der als Antwort auf einen Schaltflächenklick ausgeführt wird.

Das Datenraster unterstützt keine Initialisierung in einem ausgeblendeten übergeordneten Element, dessen Attribut 'none' ist. Wenn Sie ein Datenraster in einem ausgeblendeten übergeordneten Element mit einem Attribut 'none' initialisieren wollen, führen Sie eine erneute Wiedergabe des Rasters erst aus, wenn Sie das Datenraster aus einem ausgeblendeten übergeordneten Element anzeigen, indem Sie die Wiedergabefunktion ('Render') des Widgets aufrufen.

Das Widget 'DataGrid' bietet zwei Möglichkeiten zur Angabe, dass eine Zeile von Interesse ist:
  • Die erste Möglichkeit ist ein Mechanismus zum Auswählen von Zeilen, zum Abwählen von Zeilen und zum Abrufen der aktuellen Auswahlen.
  • Die zweite Möglichkeit ist ein Mechanismus zum Auswählen einer Gruppe von Kontrollkästchen, die automatisch bereitgestellt werden, zum Abwählen dieser Kontrollkästchen und zum Prüfen des Status dieser Kontrollkästchen.
Beide Mechanismen funktionieren unabhängig voneinander. Betrachten Sie zunächst die Möglichkeit zum Auswählen von Zeilen ('selection'):
  • Vier Funktionen werden verwendet: setSelection, selectAll, deSelectAll und getSelection.
  • Der Wert der DataGrid-Eigenschaft selectionMode gibt an, ob die Zeilenauswahl gilt, und wenn dies der Fall ist, wie viele Zeilen ausgewählt werden können. Diese Eigenschaft wirkt sich auf die Zeilenauswahl durch den Benutzer oder durch den Code aus.
  • Wenn die Zeilenauswahl gilt, werden Listenerfunktionen als Antwort auf das Klicken des Benutzers auf eine Zeile oder als Antwort auf das Aufrufen einer der folgenden Funktionen ausgeführt: setSelection, selectAll oder deSelectAll.
  • Auf die Listenerfunktionen wird durch die DataGrid-Eigenschaft selectionListeners verwiesen.
Betrachten Sie als Zweites die Möglichkeit mit Kontrollkästchen:
  • Vier Funktionen werden in Bezug auf die bereitgestellten Kontrollkästchen verwendet: setChecked, checkAll, unCheckAll und getChecked.
  • Ihr Code kann die Kontrollkästchen unabhängig davon, ob sie sichtbar sind, auswählen ('check'), abwählen ('uncheck') und verarbeiten. Sie können die Sichtbarkeit dieser Kontrollkästchen ändern, indem Sie der DataGrid-Eigenschaft showCheckBoxes einen Wert zuordnen.
  • Listenerfunktionen werden als Antwort auf die Auswahl oder Abwahl eines Kontrollkästchens durch den Benutzer oder als Antwort auf den Aufruf einer der folgenden Funktionen ausgeführt: setChecked, checkAll oder unCheckAll.
  • Auf die Listenerfunktionen wird durch die DataGrid-Eigenschaft checkBoxListeners verwiesen.

Wie erwähnt, unterstützt ein Datenraster die Spaltensortierung. Eine Sortierung erfolgt, wenn der Benutzer auf die Spaltenüberschrift klickt, jedoch nur, wenn die DataGridColumn-Eigenschaft enableSorting den Wert 'true' hat. Die Eigenschaft enableSorting hat standardmäßig den Wert 'true', und eine Sortierung ordnet den Spalteninhalt entsprechend den ASCII-Zeichenfolgewerten der Zellen an. Der Wert der DataGridColumn-Eigenschaft ignoreCase wirkt sich auch auf die Standardsortierung aus. Sie können das Sortierverhalten anpassen, indem Sie die DataGridColumn-Eigenschaft comparatorFunction festlegen und die gewünschte Funktion schreiben, auf die diese Eigenschaft verweist.

Wenn die Sortierung aktiviert ist, verweisen Sie auf die Feldgruppenwerte des Rasters nur, indem Sie auf die Eigenschaft data verweisen. Dies hat den Grund, dass die Sortierung des Benutzers die Feldgruppe nicht ändert, auf die die Eigenschaft data verweist. Im vorliegenden Beispiel hat die Sortierung des Benutzers keine Auswirkung auf die Feldgruppe stockList, während sich der folgende Ausdruck immer auf die dritte Zeile im Datenraster myGrid bezieht:
myGrid.data[3];

Neben dem Sortieren von Spalten kann der Benutzer eine Spalte ziehen und an einer anderen Position übergeben (Drag-and-drop). Diese Funktionalität ist immer aktiviert.

Wenn mehr Zeilen vorhanden sind, als Sie gleichzeitig angezeigt haben wollen, setzen Sie eine der folgenden DataGrid-Eigenschaften auf den Wert 'true':
  • showButtonBar: Diese Eigenschaften bietet dem Benutzer den Zugriff auf eine Schaltflächenleiste, d. h. eine horizontale Anzeige von Schaltflächen.
  • showScrollBar: Diese Eigenschaft ermöglicht dem Benutzer den Zugriff auf eine Schiebeleiste.
Einige der Funktionen, die in Verhalten, Listenern und Sortierungen verwendet werden, werden für Sie bereitgestellt. In den folgenden Dateien, die sich im Paket 'com.ibm.egl.rui.widgets' des Ordners 'EGLSource' im Projekt 'com.ibm.egl.rui' befinden, finden Sie entsprechende Informationen:
  • DataGridBehaviors.egl
  • DataGridFormatters.egl
  • DataGridSelector.egl
  • DataGridSorter.egl
  • DataGridToolTip.egl
Die folgenden Dateien enthalten die primäre Funktionalität für ein Datenraster:
  • DataGrid.egl
  • DataGridColumn.egl
  • DataGridLib.egl

DataGridColumn-Felder

Sie ordnen eine Feldgruppe von Datensätzen vom Typ 'DataGridColumn' zu, wenn Sie die Eigenschaft columns für ein Datenraster festlegen. Jeder dieser Datensätze enthält die folgenden Felder:
  • alignment: Eine ganzzahlige Konstante, die die horizontale Ausrichtung in der angezeigten Spalte steuert:
    DataGridLib.ALIGN_LEFT (Standardwert)
    Der Spalteninhalt wird linksbündig ausgerichtet.
    DataGridLib.ALIGN_RIGHT
    Der Spalteninhalt wird rechtsbündig ausgerichtet.
    DataGridLib.ALIGN_CENTER
    Der Spalteninhalt wird zentriert ausgerichtet.
  • columnComparator: Verweist auf eine Vergleichsoperatorfunktion während der Spaltensortierung. Eine Vergleichsoperatorfunktion wird wiederholt aufgerufen, um den Zellinhalt anzuordnen.
    Das folgende Beispiel zeigt den Stellvertreterabschnitt, dem eine angepasste Funktion entsprechen muss:
    Delegate ColumnComparator(data1 any in, data2 any in) returns (int) end
    data1
    Der Inhalt der ersten Zelle, die verglichen wird.
    data2
    Der Inhalt der zweiten Zelle.
    Die Funktion gibt den folgenden Ganzzahlwert zurück:
    • -1, wenn der Inhalt der ersten Zelle kleiner als der Inhalt der zweiten ist.
    • 1, wenn das Gegenteil der Fall ist.
    • 0, wenn der Inhalt der beiden Zellen identisch ist.
    Das folgende Beispiel zeigt eine Funktion, die verwendet werden könnte, wenn das vorherige Beispiel um die Firmennamen Company3 bis Company10 erweitert würde:
    Function CompareTwo(myFirst ANY in, mySecond ANY in) returns (int)
       if ( (myFirst as string )[8:8] == "6")
          return(-1);
       else
          return(1);  
       end
    end

    Wenn die Eigenschaft columnComparator die Funktion CompareTo angibt, platziert der Benutzerklick den Namen Company6 an den Anfang oder an das Ende der Spalte.

  • displayName: Eine Zeichenfolge, die als Spaltentitel angezeigt wird. Wenn das Feld displayName nicht angegeben wird, ist der Spaltentitel der Wert des Felds name.
  • enableSorting: Ein boolescher Wert, der angibt, ob der Benutzer die Spalte durch Klicken sortieren kann. Der Standardwert ist 'true'. Die Sortierung wird durch die Einstellung der Eigenschaft ignoreCase beeinflusst, jedoch nur, wenn Sie die Eigenschaft columnComparator nicht angeben.
  • formatters: Eine Feldgruppe von Funktionen, die in der Reihenfolge der Feldgruppenelemente ausgeführt werden, bevor das Raster wiedergegeben wird. Diese Funktionen werden einmal für jede Zelle in der Spalte ausgeführt.
    Das folgende Beispiel zeigt den Stellvertreterabschnitt, dem jede Funktion entsprechen muss:
    Delegate CellFormatter(class String inout, value String inout, rowData any in) end
    class
    Die CSS-Klasse für die Zelle in der Spalte.
    value
    Der Zelleninhalt, der immer den Typ STRING hat. Wenn der Inhalt ein Kontrollkästchen ist, ist der Wert 'true' oder 'false'.
    rowData
    Die Daten der Zeile, in der sich die Zelle befindet. Das Beispiel in der Einführung zeigt, wie die Eingaben zu behandeln sind.

    Die Funktionen für das Feld formatters werden in der Reihenfolge aufgerufen, in der die DataGridColumn-Einträge in der DataGrid-Eigenschaft columns definiert sind. Diese Funktionen werden vor den Funktionen ausgeführt, die in den folgenden DataGrid-Eigenschaften angegeben werden, die in der Laufzeitreihenfolge aufgelistet werden: headerBehaviors, behaviors und editingBehaviors.

    Eine Gruppe von Funktionen ist für die Verwendung mit der Eigenschaft formatters vorgesehen. Details finden Sie in der folgenden Datei im Paket 'com.ibm.egl.rui.widgets' des Projekts 'com.ibm.egl.rui': DataGridFormatters.egl.

  • headerAlignment: Ein ganzzahliger Wert, der die horizontale Ausrichtung in angezeigten Kopfzeile (Header) beeinflusst. Die folgenden Werte sind gültig:
    DataGridLib.ALIGN_LEFT (Standardwert)
    Der Spalteninhalt wird linksbündig ausgerichtet.
    DataGridLib.ALIGN_RIGHT
    Der Spalteninhalt wird rechtsbündig ausgerichtet.
    DataGridLib.ALIGN_CENTER
    Der Spalteninhalt wird zentriert ausgerichtet.
    Sie können alle Spaltenüberschriften festlegen, indem Sie einen Eintrag wie den folgenden in die CSS-Datei einschließen und left, center oder right für das Attribut text-align angeben:
    .EglRuiDataGridHeaderCell {
       text-align: center;
    }
  • ignoreCase: Ein boolescher Wert, der angibt, ob die Groß-/Kleinschreibung der Spalte bei der Standardsortierung ignoriert werden soll. Der Standardwert ist 'false'. Der Wert der Eigenschaft hat nur eine Wirkung, wenn Sie die Eigenschaft columnComparator nicht angeben.
  • name: Eine Zeichenfolge, die sowohl als Standardspaltentitel als auch als Name des Datensatzfelds verwendet wird, das den Spaltenwert bereitstellt.
  • sortDirection: Eine der folgenden Konstanten, die angeben, wie die nächste Sortieranforderung des Benutzers ausgeführt wird:
    DataGridLib.SORT_UP (Anfangsstandardwert)
    Durch das Klicken des Benutzers wird die Spalte aufsteigend sortiert.
    DataGridLib.SORT_DOWN
    Durch das Klicken des Benutzers wird die Spalte absteigend sortiert.
    DataGridLib.SORT_NONE
    Das Klicken des Benutzers hat keine Wirkung.

    Sie können in einer Vergleichsoperatorfunktion auf das Feld sortDirection zugreifen.

  • width: Ein ganzzahliger Wert, der die Spaltenbreite in Pixeln angibt.

DataGrid-Eigenschaften

Die folgenden Eigenschaften werden in einem Widget 'DataGrid' unterstützt:
  • behaviors: Eine Feldgruppe von Funktionsreferenzen. Die Funktionen werden bei der Wiedergabe des Datenrasters sequenziell für jede Rasterzelle aufgerufen. Diese Eigenschaft gilt nicht für die Überschriftszellen.
    Das folgende Beispiel zeigt den Stellvertreterabschnitt, dem jede Funktion entsprechen muss:
    Delegate 
       DataCellBehavior(grid DataGrid in, cell Widget in, rowData ANY in, 
                    rowNumber INT in, column DataGridColumn in)
    end
    grid
    Das Datenraster.
    cell
    Ein Widget, das die Rasterzelle darstellt. Dieses Widget basiert auf dem HTML-Tag DIV.
    rowData
    Der Datensatz, der die Zeilendaten darstellt.
    rowNumber
    Die Zeilennummer, die von 1 bis zur Gesamtzahl von Zeilen im Raster geht.
    column
    Der Datensatz, der die Spaltenbeschreibung darstellt.

    Die DataGrid-Eigenschaften werden in der folgenden Reihenfolge verarbeitet: headerBehaviors, behaviors und editingBehaviors.

  • cellBorder: Ein ganzzahliger Wert, der die Breite des Zellenrands in Pixeln angibt. Der Zellenrand befindet sich nur auf der rechten Seite der Spalte und der Wert dieser Eigenschaft gilt nicht für die letzte Spalte in jeder Zeile. Der Standardwert ist 1.
  • cellPadding: Ein ganzzahliger Wert, der die Breite der Auffüllung in Pixeln angibt, die an zwei Positionen hinzugefügt wird: über dem Inhalt in einer Zelle und links neben dem Inhalt in einer Zelle. Der Standardwert ist 4.
  • checkBoxListeners: Eine Feldgruppe von Funktionsreferenzen. Die Listenerfunktionen werden als Antwort auf die Auswahl oder Abwahl eines Kontrollkästchens durch den Benutzer oder als Antwort auf den Aufruf einer der folgenden Funktionen ausgeführt: setChecked, checkAll oder unCheckAll.
    Das folgende Beispiel zeigt den Stellvertreterabschnitt, dem jede Listenerfunktion entsprechen muss:
    Delegate 
       CheckBoxListener(grid DataGrid in) end
    end
    grid
    Das Datenraster.
    Betrachten Sie in Bezug auf das erste Beispiel im vorliegenden Abschnitt den folgenden Listener, der Börsenkürzel ('Stock Symbols') als Antwort auf die Auswahlen des Benutzers anzeigt:
    function myListener(grid DataGrid in)
       columnRetrieve Stock[];
       columnRetrieve = grid.getChecked() as Stock[];
       numberOfRows int = columnRetrieve.getSize();
    
       if (numberOfRows > 0)
          for (i int from 1 to numberOfRows)
             sysLib.writeStdOut(columnRetrieve[i].Symbol + " is checked.");
           end
       end
    end

    Details zur Einstellung von Kontrollkästchen durch Ihren Code finden Sie in der späteren Beschreibung der DataGrid-Funktionen checkAll und setChecked.

  • checkBoxWidth: Ein ganzzahliger Wert, der die Breite der vom System bereitgestellten Kontrollkästchen in Pixeln angibt. Der Standardwert ist 20.
  • columns: Eine Feldgruppe von Datensätzen vom Typ 'DataGridColumn'.
  • data: Eine Feldgruppe von Datensätzen. Die Eigenschaft hat den Typ ANY[].
  • dataLoader: Eine Funktionsreferenz. Die Funktion selbst wird nachfolgend als Datenloader bezeichnet und wird während der Ausführung wiederholt aufgerufen, um eine Untergruppe von Werten für die Anzeige im Raster bereitzustellen. In der Regel ist jede Untergruppe eine Seite von Daten und Sie setzen die Eigenschaft showButtonBar auf 'true', sodass der Benutzer von einer Seite zur nächsten klicken kann. Durch die Verwendung eines Datenloaders greifen Sie nicht auf die gesamten Daten aufeinmal, sondern auf eine Untergruppe von Daten als Antwort auf die Anforderung des Benutzers zu.
    Das folgende Beispiel zeigt den Stellvertreterabschnitt, dem jede Funktion entsprechen muss:
    Delegate DataLoader(startRow int in, endRow int in, sortFieldName string in, 
                        sortDirection int in) returns(boolean)
    end
    startRow
    Die Nummer der ersten Zeile, für die Daten angefordert werden.
    endRow
    Die Nummer der letzten Zeile, für die Daten angefordert werden.
    sortFieldName
    Der Wert des Felds name der Spalte, die der Benutzer zuletzt sortiert hat. Wenn der Benutzer keine Spalte sortiert hat, ist dieser Wert der Name der Spalte ganz links im Raster.
    sortDirection
    Eine der folgenden Konstanten, die angeben, wie die nächste Sortieranforderung des Benutzers ausgeführt wird:
    DataGridLib.SORT_UP (Anfangsstandardwert)
    Durch das Klicken des Benutzers wird die Spalte aufsteigend sortiert.
    DataGridLib.SORT_DOWN
    Durch das Klicken des Benutzers wird die Spalte absteigend sortiert.
    DataGridLib.SORT_NONE
    Das Klicken des Benutzers hat keine Wirkung.
    Der Rückgabewert gibt an, ob die Daten für die angegebenen Zeilen bereits geladen waren. Setzen Sie diesen Wert auf 'false', um anzugeben, dass Ihre Logik die Datenfeldgruppe aktualisieren wird. Setzen Sie diesen Wert auf 'true', um zu verhindern, dass der Datenloader unnötig ausgeführt wird. Ihr Code könnte zum Beispiel wie folgt aussehen:
    if (dataComplete) 
       return(true);
    else
       // Erforderliche Verarbeitung zum Hinzufügen von Daten in den angegebenen Zeilen
    end  

    Dieses Beispiel geht davon aus, dass Sie eine Variable mit dem Namen dataComplete auf den Wert 'true' setzen, nachdem ein Service alle Daten bereitgestellt hat, die angezeigt werden können. Die Bedingung in der if-Anweisung verhindert, dass der Datenloader nachfolgend weitere Aktionen in Ihrer Anwendung ausführt.

    Beachten Sie dazu die folgenden weiteren Punkte:
    • Wenn die Eigenschaft dataLoader in der DataGrid-Deklaration angegeben wird, wird der Datenloader vor der onConstruction-Funktion aufgerufen. In jedem Fall wird der Datenloader immer aufgerufen, wenn ein Wert der Eigenschaft 'data' zugeordnet wird oder wenn andere Zuordnungen erfolgen.
      Um zu verhindern, dass der Datenloader auf Rich-UI-Handlerfelder zugreift, bevor diese initialisiert wurden, lassen Sie die Eigenschaften data und dataLoader aus der DataGrid-Deklaration weg. Fügen Sie Anweisungen wie die folgenden beiden am Ende der onConstruction-Funktion ein:
      myGrid.dataLoader = myDataLoader;
      myGrid.data = myDataList as ANY[];
    • Der Prozess des Ladens einer Teilmenge von Daten beginnt mit einem Aufruf des Datenloaders und wird fortgesetzt, während Werte in die Datenfeldgruppe eingefügt werden. Sie können den Prozess beenden, indem Sie die rasterspezifische Funktion render aufrufen. Dies kann zum Beispiel in der Rückruffunktion geschehen, die Sie zum Abrufen von Daten aus einem Service einrichten.
    • Wenn der Datenloader keine Daten für eine bestimmte Gruppe von Zeilen empfangen kann, rufen Sie die rasterspezifische Funktion cancelDataLoader auf. Dies kann zum Beispiel in der Ausnahmebehandlungsroutine geschehen, die Sie einrichten, um auf einen Servicefehler zu antworten.
    • Die Verwendung einer Schaltflächenleiste funktioniert am besten, wenn Sie eine vollständige Datenfeldgruppe früh in der Verarbeitung angeben, auch wenn der Inhalt dieser Feldgruppe erst mit dem Klicken des Benutzers auf die Schaltflächenleiste bereitgestellt wird. Sie können die Anzahl von Elementen vorab festlegen und dann jedoch einen Prozess wie den folgenden ausführen: Sie fügen ein einzelnes Element in die Datenfeldgruppe ein und rufen dann die endgültige Anzahl der Elemente während des ersten Aufrufs eines Service mit Zustandsüberwachung (STATEFUL) auf.

    Ein Beispiel für die Verwendung der Eigenschaft dataLoader finden Sie im Abschnitt “End-to-End-Verarbeitung mit einem UI-Programm und einem Datenraster”.

  • editorBehaviors: Eine Feldgruppe von Funktionsreferenzen. Die Funktionen werden bei der Wiedergabe des Datenrasters sequenziell für jede Zelle aufgerufen. Sie haben den Zweck, ein Widget in jede Zelle einzufügen.
    Das folgende Beispiel zeigt den Stellvertreterabschnitt, dem jede Funktion entsprechen muss:
    Delegate 
       EditorBehavior(grid dataGrid in, cell Widget in, rowData any in, 
                      rowNumber INT in, column DataGridColumn in, value ANY in) 
                      returns (Widget)
    end
    grid
    Das Datenraster.
    cell
    Ein Widget, das die Rasterzelle darstellt. Dieses Widget basiert auf dem HTML-Tag DIV. Sein Inhalt beinhaltet die Effekte (sofern zutreffend), die durch die Einstellung der Eigenschaft formatters angegeben werden.
    rowData
    Der Datensatz, der die Zeilendaten darstellt.
    rowNumber
    Die Zeilennummer, die von 1 bis zur Gesamtzahl von Zeilen im Raster geht.
    column
    Der Datensatz, der die Spaltenbeschreibung darstellt.
    value
    Der Inhalt der Zelle. Dieser Inhalt beinhaltet die Effekte (sofern zutreffend), die durch die Einstellung der DataGridColumn-Eigenschaft formatters angegeben werden.

    Der Rückgabewert ist ein Widget oder 'null'.

    Die DataGrid-Eigenschaften werden in der folgenden Reihenfolge verarbeitet: headerBehaviors, behaviors und editingBehaviors.

  • headerBehaviors: Eine Feldgruppe von Funktionsreferenzen. Die Funktionen werden bei jeder Wiedergabe des Datenrasters sequenziell für jede Überschriftszelle aufgerufen. Jede Funktion basiert auf dem Stellvertreterabschnitt, der im Eintrag für die Eigenschaft behaviors beschrieben wird.
  • pageSize: Ein ganzzahliger Wert, der angibt, wie viele Zeilen angezeigt werden sollen. Der Standardwert ist 10. Detaillierte Informationen finden Sie in den Einträgen für die Eigenschaften showButtonBar und showScrollBar.
  • rowHeight: Ein ganzzahliger Wert, der die minimale Höhe in Pixeln einer Zeile angibt. Wenn ein Inhalt vertikal mehr Platz benötigt, berücksichtigt die Höhe der Zeile den Bedarf.
  • selectionListeners: Eine Feldgruppe von Funktionsreferenzen. Wenn die Zeilenauswahl gilt, werden die Auswahllistener als Antwort auf das Klicken des Benutzers auf eine Zeile oder als Antwort auf das Aufrufen einer der folgenden Funktionen ausgeführt: setSelection, selectAll oder deSelectAll.
    Das folgende Beispiel zeigt den Stellvertreterabschnitt, dem jede Auswahllistenerfunktion entsprechen muss:
    Delegate 
       SelectionListener(grid DataGrid in) end
    end
    grid
    Das Datenraster, das an die Funktion übergeben wird.
    Betrachten Sie in Bezug auf das erste Beispiel im vorliegenden Abschnitt den folgenden Listener, der Börsenkürzel ('Stock Symbols') als Antwort auf die Auswahlen des Benutzers anzeigt:
    function myListener(grid DataGrid in)
       columnRetrieve Stock[];
       columnRetrieve = grid.getSelection() as Stock[];
       numberOfRows int = columnRetrieve.getSize();
    
       if (numberOfRows > 0)
          for (i int from 1 to numberOfRows)
             sysLib.writeStdOut(columnRetrieve[i].Symbol + " is selected.");
           end
       end
    end

    Details zur Zeilenauswahl in Ihrem Code finden in der späteren Beschreibung der DataGrid-Funktionen selectAll und setSelection.

  • sortListeners: Eine Feldgruppe von Funktionsreferenzen. Die Funktionen werden sequenziell aufgerufen, wenn der Benutzer eine Spalte sortiert. Die Funktionen werden nur aufgerufen, wenn eine Sortierung erfolgt, was nur möglich ist, wenn die DataGrid-Eigenschaft enableSort den Wert 'true' hat.
    Das folgende Beispiel zeigt den Stellvertreterabschnitt, dem jede Funktion entsprechen muss:
    Delegate 
       SortListener(grid DataGrid in, sortColumn DataGridColumn in) end
    end
    grid
    Das Datenraster, das sortiert wurde.
    sortColumn
    Die Spalte, die sortiert wurde.

    Im folgenden Beispiel wird diese Funktion verwendet:

    function mySortListener(grid DataGrid in, sortColumn DataGridColumn in)
       syslib.writeStdOut("You sorted the " + sortColumn.displayName + " column. ");
    end
  • startRow: Ein ganzzahliger Wert, der eine Zeile zum Anzeigen auf der ersten Seite angibt, wenn eine Schaltflächenleiste vorhanden ist. Der Standardwert ist 1. Weitere Informationen finden Sie im Eintrag für showButtonBar.
  • selectionMode: Eine Konstante, die angibt, ob der Benutzer oder der Code mehrere Zeilen auswählen kann. Diese Konstante gibt außerdem an, ob die Funktionen setSelection und selectAll mehrere Zeilen auswählen können. Gültige Werte:
    DataGridLib.MULTIPLE_SELECTION (Standardwert)
    Der Benutzer kann eine einzelne Zeile oder mehrere Zeilen mit einer von zwei Methoden auswählen:
    • Drücken und Halten der Steuertaste (Strg) beim Anklicken der weiteren Zeilen nach der ersten Zeile
    • Durch Drücken und Halten der Umschalttaste beim Anklicken der letzten Zeile in einer zusammenhängenden Gruppe von Zeilen

    Die ausgewählten Zeilen können sich über mehrere Rasterseiten erstrecken.

    DataGridLib.SINGLE_SELECTION
    Der Benutzer kann eine einzelne Zeile auswählen. Die Auswahl einer zweiten Zeile hat zur Folge, dass zunächst die erste Zeile wieder abgewählt wird.
    DataGridLib.DISABLE_SELECTION
    Der Benutzer kann überhaupt keine Zeilen auswählen.
  • showButtonBar: Ein boolescher Wert, der angibt, ob eine Schaltflächenleiste eingeschlossen werden soll. Dabei handelt es sich um eine Navigationsleiste am unteren Ende des Rasters, in der der Benutzer auf eine andere Seite klicken kann, um zur nächsten, vorherigen oder zur letzten Seite zu gelangen. Wenn die Eigenschaft showButtonBar den Wert 'true' hat, sind auch die folgenden Eigenschaften relevant:
    • pageSize: Gibt an, wie viele Zeilen gleichzeitig angezeigt werden sollen.
    • startRow: Gibt an, welche Zeile dem Benutzer angezeigt werden muss. Beispiel: Wenn 20 Zeilen vorhanden sind und pageSize = 4 und startRow = 6 angegeben wird, wird die zweite Seite mit Zeile 6 an zweiter Position angezeigt.
    Die Eigenschaft showButtonBar kann nur im folgenden Fall eine Wirkung haben:
    • Der Wert der Eigenschaft pageSize ist größer als die Anzahl der Zeilen, die für das Raster verfügbar sind. Und:
    • Die Eigenschaft showScrollBar hat den Wert 'false'.

    Wenn Sie die Eigenschaft showButtonBar auf 'false' setzen und mehr Zeilen verfügbar sind, als sichtbar gemacht werden können und wenn Sie die Eigenschaft showScrollBar nicht auf 'true' setzen, kann der Benutzer nicht auf die nicht sichtbaren Zeilen zugreifen.

  • showCheckBoxes: Ein boolescher Wert, der angibt, ob die vom System bereitgestellten Kontrollkästchen sichtbar gemacht werden sollen. Der Standardwert ist 'false'. Wenn die Kontrollkästchen sichtbar sind, werden sie auf der linken Seite jeder Zeile angezeigt.
    Die Kontrollkästchenauswahlen des Benutzers werden beibehalten, auch wenn Sie die Eigenschaft showCheckBoxes während der Ausführung auf 'false' setzen. Darüber hinaus haben Sie im Code immer die folgenden Möglichkeiten, unabhängig davon, ob die Kontrollkästchen sichtbar sind:
    • Sie können einige oder alle der ausgeblendeten Kontrollkästchen auswählen, indem Sie die Funktion setChecked oder checkAll aufrufen.
    • Sie können die Funktion getChecked verwenden, um den Status der Kontrollkästchen in jeder Zeile zu prüfen.
  • showHeader: Ein boolescher Wert, der angibt, ob die Rasterkopfzeile (Header) angezeigt werden soll. Der Standardwert ist 'true'.
  • showScrollBar: Ein boolescher Wert, der angibt, ob die Zeilen mit einer Schiebeleiste angezeigt werden sollen, sodass der Benutzer zu anderen Zeilen navigieren kann. Der Standardwert ist 'false'. Wenn diese Eigenschaft den Wert 'true' hat, gibt die Eigenschaft pageSize an, wie viele Zeilen gleichzeitig angezeigt werden sollen, und die Eigenschaft showButtonBar hat keine Wirkung.
  • manageEditorBehaviors: Ein boolescher Wert, der angibt, ob der Lebenszyklus der Editorverhaltenswidgets, die vom Stellvertreter 'editorBehavior' zurückgegeben werden, durch das Raster verwaltet werden. Der Standardwert ist 'true'.
  • refreshBehaviors: Eine Feldgruppe von Funktionsreferenzen. Die Funktionen werden bei jeder Wiedergabe des Datenrasters sequenziell aufgerufen.

DataGrid-Funktionen

Die folgenden Funktionen werden im DataGrid-Widget unterstützt:
  • cancelDataLoader: Wird in erster Linie in einer Ausnahmebehandlungsroutine verwendet, um anzugeben, dass die vom Datenloader benötigten Daten nicht verfügbar sind. Die Funktion cancelDataLoader stoppt keine nachfolgenden Aufrufe des Datenloaders, sondern hat zwei Wirkungen: Sie beendet die für einen wartenden Datenloader typische Animation und stellt das Raster mit den Daten erneut dar, die zuletzt bereitgestellt wurden.
  • checkAll: Dient zum Auswählen aller vom System bereitgestellten Kontrollkästchen. Sie können die Kontrollkästchen auswählen, auch wenn sie ausgeblendet sind.
  • deSelectAll: Dient zum Abwählen aller Zeilen, die zurzeit ausgewählt sind. Diese Funktion gehört zum Zeilenauswahlmechanismus, der von den durch das System bereitgestellten Kontrollkästchen unabhängig ist.
  • getChecked: Dient zum Abrufen der Daten in den Zeilen, bei denen die vom System bereitgestellten Kontrollkästchen ausgewählt sind. Die Funktionssignatur sieht wie folgt aus:
    function getChecked() returns (any[])
    Betrachten Sie in Bezug auf das erste Beispiel im vorliegenden Abschnitt den folgenden Ereignishandler, der Börsenkürzel ('Stock symbols') anzeigt:
    function myResponse (e event in)
       columnRetrieve Stock[];
       columnRetrieve = grid.getChecked() as Stock[];
       numberOfRows int = columnRetrieve.getSize();
    
       if (numberOfRows > 0)
          for (i int from 1 to numberOfRows)
             sysLib.writeStdOut(columnRetrieve[i].Symbol + " is checked.");
          end
       end
    end

    Die Funktion getChecked ruft die Datensätze ab, die von der DataGrid-Eigenschaft data referenziert werden. Allerdings hängt die Reihenfolge, in der die Daten zurückgegeben werden, von der aktuellen Anzeige ab, die durch die Sortierung des Benutzers beeinflusst wird.

  • getCurrentPageIndex: Dient zum Abrufen der aktuellen Seitennummer. Die Funktionssignatur sieht wie folgt aus:
    function getCurrentPageIndex() returns (int)
  • getPageCount: Dient zum Abrufen der Anzahl verfügbarer Seiten. Die Funktionssignatur sieht wie folgt aus:
    function getPageCount() returns (int)
  • getSelection: Dient zum Abrufen der Daten in den zurzeit ausgewählten Zeilen. Die Funktionssignatur sieht wie folgt aus:
    function getSelection() returns (any[])
    Betrachten Sie in Bezug auf das erste Beispiel im vorliegenden Abschnitt den folgenden Ereignishandler, der Börsenkürzel ('Stock Symbols') als Antwort auf das Klicken auf eine Schaltfläche durch den Benutzer anzeigt:
    function myResponse (e event in)
       columnRetrieve Stock[];
       columnRetrieve = grid.getSelection() as Stock[];
       numberOfRows int = columnRetrieve.getSize();
    
       if (numberOfRows > 0)
          for (i int from 1 to numberOfRows)
             sysLib.writeStdOut(columnRetrieve[i].Symbol + " is selected.");
          end
          grid.deSelectAll();
       else
          sysLib.writeStdOut("Select one or more rows.");                    
       end 
    end

    Die Funktion getSelection ruft die Datensätze ab, die von der DataGrid-Eigenschaft data referenziert werden. Allerdings hängt die Reihenfolge, in der die Daten zurückgegeben werden, von der aktuellen Anzeige ab, die durch die Sortierung des Benutzers beeinflusst wird.

  • goToPage: Dient zum Anzeigen der angegebenen Seite. Wenn Sie eine Seitennummer angeben, die kleiner oder gleich 1 ist, wird die erste Seite angezeigt. Wenn Sie eine Seitennummer angeben, die größer oder gleich der Nummer der letzten Seite ist, wird die letzte Seite angezeigt.
    Die Funktionssignatur sieht wie folgt aus:
    function goToPage(pageNumber int in)
  • selectAll: Dient zum Auswählen aller Zeilen im Datenraster.
  • setChecked: Dient zum Auswählen eines oder mehrerer der vom System bereitgestellten Kontrollkästchen. Sie können Kontrollkästchen auswählen, auch wenn sie ausgeblendet sind.
    Die Funktionssignatur sieht wie folgt aus:
    function setChecked(selection any[] in)
    Wenn Sie die Funktion setChecked aufrufen, geben Sie Elemente aus der Datenfeldgruppe an. Das folgende Beispiel zeigt eine onConstruction-Funktion, die die Funktion setChecked auf zwei Arten aufruft:
    function start()
    
    	  grid.setChecked([grid.data[2], grid.data[3]]);
    
       // Alternative Codierung
       myAny ANY[] = [grid.data[2], grid.data[3]];
       grid.setChecked(myAny);
    end
  • setSelection: Dient zum Auswählen einer oder mehrerer Zeilen im Datenraster. In den meisten Fällen hat dies den Zweck, das Raster vorab festzulegen, bevor es wiedergegeben wird. Die Funktionssignatur sieht wie folgt aus:
    function setSelection(selection any[] in)
    Wenn Sie die Funktion setSelection aufrufen, geben Sie Elemente aus der Datenfeldgruppe an. Das folgende Beispiel zeigt eine onConstruction-Funktion, die die Funktion setSelection auf zwei Arten aufruft:
    function start()
    
    	  grid.setSelection([grid.data[3], grid.data[2]]);
    
       // Alternative Codierung
       myAny ANY[] = [grid.data[3], grid.data[2]];
       grid.setSelection(myAny);
    end

    Die Möglichkeit zur Auswahl von Zeilen hängt von der Einstellung der DataGrid-Eigenschaft selectionMode ab. Zum Beispiel wird nur der erste Eintrag, der an die Funktion setSelection übergeben wird, ausgewählt, wenn Ihr Code versucht, zwei Zeilen auszuwählen, und die Eigenschaft selectionMode nur eine Auswahl zulässt.

  • unCheckAll: Dient zum Abwählen aller vom System bereitgestellten Kontrollkästchen. Sie können die Kontrollkästchen abwählen, auch wenn sie ausgeblendet sind.

DataGrid-QuickInfos

Wenn Sie eine QuickInfo (bzw. Kurzinfo) für ein Datenraster einfügen wollen, stehen zwei Hauptalternativen zur Verfügung:
  • Wenn die QuickInfo immer angezeigt werden soll, wenn sich der Cursor über dem Datenraster befindet, und nicht nach Zelle, Zeile oder Spalte variieren soll, ordnen Sie das Datenraster als Ganzes einer QuickInfo (Tooltip) zu. Detaillierte Informationen dazu finden Sie in “Rich-UI-Widget 'Tooltip'”. Sie könnten ein Widget 'Tooltip' als globales Widget deklarieren und in einer Funktion aktivieren, wie zum Beispiel in der onConstruction-Funktion oder einer Funktion, die in der Eigenschaft behaviors oder headerBehaviors angegeben wird.
  • Wenn die QuickInfo für eine bestimmte Zelle, Zeile oder Spalte außerhalb der Kopfzeile unterschiedliche Informationen anzeigen soll, können Sie eine DataGridTooltip-QuickInfo angeben, die ähnlich wie eine QuickInfo funktioniert, jedoch immer erfordert, dass Sie eine GridTooltip-Providerfunktion angeben. Diese Funktion gibt ein Feld zurück, das den Inhalt bereitstellt, der dem Benutzer angezeigt werden soll. Sie können nur eine QuickInfo angeben.
Eine DataGridTooltip-QuickInfo wird wie folgt erstellt:
  • Deklarieren Sie einen GridTooltip-Handler wie im folgenden Beispiel, der einen Raster-QuickInfo-Provider (die aufzurufende Funktion) und eine Verzögerung (die Anzahl Millisekunden zwischen dem Beginn der Mausbewegung über dem Widget und dem Aufruf des Providers) angibt:
    gridTooltip DataGridTooltip { provider = tooltipText, tooltip.delay = 1000 };
    Diese Deklaration erfordert den Einschluss der folgenden Anweisung 'import':
    import egl.rui.widgets.DataGridToolTip;
  • Referenzieren Sie eine Funktion im GridTooltip-Handler, wenn Sie eine Feldgruppe für die Eigenschaft behaviors zuordnen. In diesem Beispiel hat die Funktion den Namen gridToolTip.setToolTips.
  • Erstellen Sie eine GridTooltip-Providerfunktion mit dem Namen, der in der DataGridToolTip-Eigenschaft provider angegeben ist (in diesem Beispiel heißt die Funktion tooltipText). Die GridTooltip-Providerfunktion hat die Parameter- und Rückgabewertmerkmale, die im folgenden Stellvertreterabschnitt gezeigt werden:
    Delegate DataGridTooltipTextProvider(rowData any in, fieldName String in, 
                                         td Widget in) returns(Box)
    end
    row
    Die Zeile, die für die Funktion angegeben wird. Sie können das Eingabeargument verwenden, um auf einen bestimmten Wert zuzugreifen. Betrachten Sie zum Beispiel den Fall, in dem die folgenden Daten verwendet werden:
    stocks Stock[] = [
    		 new Stock{Symbol = "Company1", Quote = 100, NumShares = 40, SelectQuote = false}, 
    		 new Stock{Symbol = "Company2", Quote = 200, NumShares = 10, SelectQuote = false}
    	]; 
    In der Providerfunktion können Sie bestimmen, auf welcher Zeile sich der Mauszeiger befindet, indem Sie Code wie den folgenden schreiben:
    if (rowData.Quote as int == 200)
       // Inhalt in ein Feld (QuickInfo) einfügen und die QuickInfo zurückgeben
    end
    fieldName
    Der Name der Spalte, die für die Funktion angegeben wird.
    td
    Ein internes Widget, das die Rasterzelle darstellt.
  • Sie aktivieren die DataGridTooltip-QuickInfo nicht, da sie aktiviert wird, sobald Sie sie deklarieren.
  • Beachten Sie das Problem, das in “Rich-UI-Speicherverwaltung” beschrieben wird.

Beispiel

Das folgende Beispiel können Sie in Ihrem Arbeitsbereich ausprobieren:

package client;

import com.ibm.egl.rui.widgets.Box;
import com.ibm.egl.rui.widgets.DataGrid;
import com.ibm.egl.rui.widgets.DataGridColumn;
import com.ibm.egl.rui.widgets.DataGridTooltip;
import com.ibm.egl.rui.widgets.TextArea;
import egl.ui.rui.RUIHandler;

Record Stock 
   Symbol STRING;
   Quote  DECIMAL(5,2); 
   NumShares INT;
end

handler MyDataGrid1 type RUIhandler { initialUI = [ grid ], 
                                      onConstructionFunction = start }
   stockList Stock[] = [
      new Stock{Symbol = "Company1", Quote = 100.00, NumShares = 40 }, 
      new Stock{Symbol = "Company2", Quote = 200.00, NumShares = 10 },
      new Stock{Symbol = "Company3", Quote = 100.00, NumShares = 40 } ]; 

   grid DataGrid { 
      data = stockList as any[],
      behaviors = [myDataGridToolTip.setToolTips],
      pageSize = 15,
      columns = [
         new DataGridColumn { name = "Symbol", displayName = "Symbol Display"},    
         new DataGridColumn { name = "Quote", displayName = "Quote Display"},
         new DataGridColumn { name = "NumShares", displayName = "NumShares Display"  }]};

   myDataGridTooltip DataGridTooltip { provider = tooltipText, tooltip.delay = 1000 };

   tooltipBox Box{columns=1, width=475};

   function start()
   
   end
    
   function tooltipText (rowData any in, fieldName String in, td Widget in) returns (Box)
	
      tooltipArea TextArea { width=450, height=100, paddingLeft=7, marginLeft=7 };
      tooltipBox.children = [ tooltipArea ];	
      tooltipArea.text = 
      "In function tooltipText (a tooltip provider):" + 
      "\n   fieldName is the column name ('"+fieldName+"')." +
      "\nYou can access cell content:" +
      "\n   td.innerText is '"+td.innerText+"'. \nThanks to EGL dynamic access" +
      "\n   rowData[fieldName] is also '"+rowData[fieldName] + "'."; 
      return (tooltipBox); 
   end
end

Feedback