Statusanzeige (Datentyp Dialog)

Veröffentlicht: 27. Oktober 2010 in Tipp

Die Statusanzeige! Ja, wer hätte nicht manchmal gerne eine schöne Progressbar.

Ersteinmaml etwas Allgemeines zu Dialogen: Jede Dialog Variable kann Felder haben. Diese Felder werden durch „#“ (für einfache TextBoxen) oder „@“ (für Progressbar, Statusbalken) Kennzeichnet und bekommen eine eindeutige ID. Mit Hilfe der ID können die Felder mit dem UPDATE Befehl gefüllt werden. Diese UPDATEs des Dialogs brauchen etwas Zeit. Progressbars haben einen Wert von 0 (0%) bis 1000 (100%). Diese Einstufung wurde (vermutlich) erstellt um möglichst genaue Werte anzeigen zu können. Falls irgendwer was genaueres bzw. technischeres weiss, bitte im Kommentar verewigen 🙂

Außerdem sollte man ein paar Kleinigkeiten bei den Dialogen in NAV beachten. Zu allererst einmal: Lohnt es sich einen Dialog anzuzeigen? Diese sind zwar schön aber brauchen auch Performance und das nicht mal wenig. Des Weiteren sollte man immer eine Variable (z.B. HideDialog) von außen setzen können, sodass die Dialoge ausgeschaltet werden können, falls man mal diese Funktion im Hintergrund starten möchte. Ausserdem kann man diese dann auch für einen Webservice oder dem NAS verwenden.

Dann würde ich dazu raten keine Globalen Variablen vom Typ Dialog anzulegen. Wenn nämlich dann ein Fehler in einer der Subfunktionen entsteht, bleibt der Dialog offen als wenn noch etwas verarbeitet wird. Also, merken: auch in Codeunits, pro Funktion eine lokale Dialog Variable anlegen. Wenn man sehr viele Daten zu verarbeiten hat, ist eine Statusanzeige sinnvoll aber braucht halt auch die oben genannte Leistung. Dieser Performance Verlust wird bedingt durch das UPDATE auf die Dialog Felder bzw. des Dialogs. Aber später erläutere ich eine Vorgehensweise, wie man große Datenmengen mit Dialogen angenehm anzeigen kann und die UPDATES auf ein nötiges zu reduzieren.

Im nun folgendem Code, gehen wir davon aus das eine lokale Variable vom Typ Dialog namens dlg existiert.

Ein Dialog an und für sich:

dlg.OPEN('Benutzer:       #1############\Debitoren Name: #2####################');
dlg.UPDATE(1, USERID);
Customer.RESET;
IF Customer.FINDSET THEN BEGIN
 FOR i := 1 TO Customer.COUNT DO BEGIN
 dlg.UPDATE(2, Customer.Name);
 sleep(100);
 Customer.NEXT(1);
 END;
END;
dlg.close();

Dieser Code zeigt nur schnell alle Debitoren Namen an und schliesst sich wieder. Relativ simple wenn mans weiss, oder? 🙂 Der Sleep ist nur da, da meine Cronus Datenbank nur 73 Debitoren hatte und ich die Namen auch lesen können wollte.

Das Nächste ist ein simpler Statusbalken:

dlg.OPEN('Gesamtanzahl Debitoren: #1#########\Verarbeit:              #2#############\Verarbeitung:           @3@@@@@@@@@@@@@');
Customer.RESET;
dlg.UPDATE(1, Customer.COUNT);
IF Customer.FINDSET THEN BEGIN
 for i := 1 to Customer.COUNT DO BEGIN
 dlg.UPDATE(2, i);
 dlg.UPDATE(3, ROUND((i / Customer.COUNT) * 10000, 1) );
 sleep(100);
 Customer.NEXT(1);
 END;
END;
dlg.close();

Wie man hier schon sieht, wird für den Statusbalken das Steuerzeichen/Feldzeichen (oder wie auch immer :))  „@“ verwendet. Um den Statusbalken dazu zu bringen, dass er sich füllt, muss man das Feld 3 mit 100er Schritten füllen (wenn man 1% schritte möchte). Man kann sagen, der Wert 100 sind 1% also heisst das 10000 sind gleich 100%. Um diese Schritte darzustellen, gibt es die simple Formel:

(AktuelleAnzahl / MaximaleAnzahl) * 10000

Das dann noch auf glatte Zahlen runden und es gibt die 100er Schritte, die immer genau den 1%  Fortschritt anzeigen.Und genau diese Formel (keine höhere Mathematik :)) habe ich im Code für den Statusbalken verwendet.

Als letztes möchte ich noch beschreiben, wie man nun große Datenmengen verarbeitet und den Performance-Fresser-Dialog etwas ausbremsen kann. Dies kann relativ sinnvoll wie folgt gestaltet werden:

Zu allererst benötigen wir zusätzlich folgende Variablen:

  • NewProgress    Integer
  • OldProgress    Integer
  • MillisecondsDuration    Integer

und daraufhin den folgenden Code:

dlg.OPEN('Gesamt Anzahl:          #1#########\Verarbeit:              #2#############\Verarbeitung:           @3@@@@@@@@@@@@@');
dlg.UPDATE(1, 10000);

LastTime := CURRENTDATETIME;
for i := 1 TO 10000 DO BEGIN
 sleep(5);
 dlg.UPDATE(2, i);
 MillisecondsDuration := 3000; // Integer Datentyp
 IF (CurrentDateTime - LastTime > MillisecondsDuration) OR (CurrentDateTime < LastTIme) THEN BEGIN
   NewProgress := ROUND((i / 10000) * 10000,1);
   IF NewProgress <> OldProgress THEN BEGIN
     dlg.UPDATE(3, NewProgress);
     OldProgress := NewProgress;
   END;
   LastTime := CurrentDateTime;
 END;
END;

Dieser Code bewirkt, dass das dritte Feld nur alle 3 Sekunden (MillisecondsDuration) befüllt wird, was bedeutet das dieser Dialog auch sehr viel weniger geupdatet wird und somit Zeit gespart wird.

Falls es noch Fragen, Kommentare, Anmerkungen oder Korrekturen gibt, lasst euch bitte im Kommentar Bereich aus :).

Euch noch einen schönen Abend,

Matthias König

 

EDIT: Heute ist bei der Statusanzeige in der Version „Performance-Fresser-Dialog“ ein kleiner Fehler aufgefallen. Im RTC würde dieser Code so nicht funktionieren da ein Fehler „Das Datum ist ungültig“ (o.ä.) auftauchen würde. Das liegt daran, das LastTime noch nicht initialisiert worden ist und der RTC, warum auch immer, ein Problem damit hat 0DT von einer DateTime abzuziehen. Der Code wurde also geupdated!

Advertisements
Kommentare
  1. Engelhuber sagt:

    Hi Mattes,

    schau doch mal bitte ins MSDynamics Forum.
    Hab dir eine PM geschrieben…

    Gruß
    Christoph

    • König sagt:

      Moin Christoph,

      da will ich in Ruhe drauf Antworten, habe dafuer derzeit allerdings keine Zeit :(. Werde versuchen Morgen oder uebers Wochenende dir bescheid zu geben!

      Gruß,
      Matthias König

  2. Sebastian sagt:

    Bei der Progressbar ist es nicht der Bereich 0 bis 1000 welcher gültig ist, sondern 0 bis 9999.

    Gruß,
    Sebastian

    • König sagt:

      Hallo Sebastian,

      wenn man die 0 Inklusive rechnet, hast du natuerlich Recht. 🙂 Werte über die 9999 nimmt der Dialog allerdings auch an, sowie auch unter 0.

  3. Natalie sagt:

    Wozu braucht man die Dinger?
    Naja, der Benutzer muss auch die Möglichkeit erhalten, einen langen Prozess abzubrechen. Ohne Dialog kein Abbruch-Button!

    Damit man jedoch eine Chance bekommt, den Button überhaupt zu erwischen, sollte man den UPDATE-Befehl in gewissen Abständen absetzen (z.B alle 2 Sekunden).
    Wie das geht, hast du ja schon erläutert.

    Und sowas diskutierst du nicht bei uns? Ich bin geschockt 🙂

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s