This website uses cookies for visitor traffic analysis. By using the website, you agree with storing the cookies on your computer.More information

Progress Bar (Ladebalken)

Allgemeine Fragen zur Entwicklung von und mit JVx.

Progress Bar (Ladebalken)

Postby hansemar » Thu Aug 02, 2018 1:59 pm

Hallo,

in der Dokumention wird beschrieben wie eine UIProgressBar Componente erstellt und im Workscreen verwendet werden kann: Custom Components

Ich möchte diese UIProgressBar Componente in einen Popup-Fenster anzeigen lassen. Wie bekomme ich den Fortschritt, welchen ich in einer Prozedur innerhalb des Workscreens ermittle, an das Popup-Fenster weitergegeben? Und muss dieses Popup-Fenster jedesmal neu gerendert werden damit der Ladebalken den aktuellen Bearbeitungsstand anzeigt?

Gruß Mark
hansemar
 
Posts: 15
Joined: Tue Jun 26, 2018 10:46 am

Re: Progress Bar (Ladebalken)

Postby Support@SIB » Wed Aug 08, 2018 2:42 pm

Das sollte keine Hexerei sein. Entweder Sie verwenden einen Thread und aktualisieren den Balken (via invokeLater) oder Sie setzen den Value des Balkens zu definierten Zeitpunkten.

Im Normalfall wird ein Progress aber innerhalb eines Threads geändert. Sie müssen ja vermutlich den aktuellen Wert ermitteln und dann den Status weitersetzen? Damit das GUI nicht blockiert (im Falle von Swing), ist ein Thread die Lösung.

Mit Vaadin UI ist das auch kein Problem, wenn Sie Push aktiviert haben. Damit ist das ganze dann auch ohne Probleme machbar.

Ein ständiges Rendern ist nicht nötig, lediglich den Value des Progressbars setzen ist ausreichend.
User avatar
Support@SIB
 
Posts: 353
Joined: Mon Sep 28, 2009 1:56 pm

Re: Progress Bar (Ladebalken)

Postby Support@SIB » Wed Aug 08, 2018 2:52 pm

Sie müssen natürlich Thread Safe sein im Falle von mehreren Threads. Sprich synchronized nicht vergessen. Wenn Sie auf Datenbankfunktionen zugreifen, dann sollten Sie unbedingt eine eigene MasterConnection verwenden für die Abfragen.
User avatar
Support@SIB
 
Posts: 353
Joined: Mon Sep 28, 2009 1:56 pm

Re: Progress Bar (Ladebalken)

Postby rzenz » Thu Aug 09, 2018 10:31 am

Die wichtige Frage hierbei ist: Wo passiert die Arbeit, am Client oder Server?

Wenn die Operation am Server durchgefuehrt wird ist es ein leichtes den Status mit einem Balken angezeigt zu bekommen. Nehmen wir an wir haben eine lange Operation die am Server laeuft und eine grosze Anzahl an Datensaetzen verarbeitet.

Code: Select all
public void process()
{
    for (IBean row : getStorage().fetchBean(null, null, 0, -1))
    {
        processRow(row);
    }
}


Vom Client aus wird diese normal ueber die Verbindung aufgerufen.

Code: Select all
getConnection().callAction("process");


Nun hat man hier genau das Problem dass der Aufruf blockiert bis alle Datensaetze abgearbeitet sind. Der erste Schritt ist es den Aufruf asynchron zu machen mit einem Callback.

Code: Select all
getConnection().callBackAction(this, "onProcessFinished", "process");


Damit hat man nun die Information wann die Operation fertig wird und der Thread wird nicht blockiert. Fehlt nur noch dass man den Status mitbekommt, das geht aber recht einfach. Auf der Server Seite fuegt man die Moeglichkeit ein den Status zu erhalten (der Einfachheit halber nehme ich nun Prozent).

Code: Select all
private double progress = 0.0d; // Range: 0.0d - 1.0d

public double getProgress()
{
    return progress;
}

public void process()
{
    progress = 0.0d;
   
    int rowCounter = 0;
   
    List<IBean> rows = getNeededStorage().fetchBean(null, null, 0, -1);
   
    for (IBean row : rows)
    {
        processRow(row);
        progress = ++rowCounter / (double)rows.size();
    }
   
    progress = 1.0d;
}


Dann kann man auf der Client Seite den Zustand der Operation abfragen.

Code: Select all
getConnection().callAction("getProgress");


Der Rest ist Zustandsverwaltung auf der Client Seite.

Falls die Operation auf der Client Seite stattfindet wird die Sache geringfuegig komplizierter da man die Operation vom GUI Thread auslagern muss. Da ist dann darauf zu achten dass man keine Thread uebergreifende Zugriffe auf die Connection, DataBooks oder vergleichbar hat. Ansonsten ist es eine recht geradeaus Implementierung, wichtig ist hierbei wieder die Arbeit aus dem GUI Thread zu verlagern und diesen kann man dann ueber invokeLater ansteuern.

Code: Select all
public void process(IProgressReport progressReporter)
{
    for (int index = 0, rowCount = dataBook.getRowCount(); index < rowCount; index++)
    {
        dataBook.setSelectedRow(index);
        processRow(dataBook);
       
        progressReporter.report(index / (double)rowCount);
    }
}

process((pProgress) ->
{
    getFactory().invokeLater(() ->
    {
        progressBar.setProgress(pProgress);
    });
});


invokeLater fuehrt den Code dann zum "naechst besten" Zeitpunkt auf dem GUI Thread aus, was in Swing dann ist wenn alle Ereignisse aus der EventQueue abgearbeitet worden sind. Auch hier braucht man natuerlich eine Zustandsverwaltung die richtig reagiert wenn die Operation beginnt, waehrend dessen und auch wenn diese beendet wurde. Also am Anfang das oeffnen des Fensters mit dem Balken und wenn die Operation fertig ist, dass dieses wieder geschlossen wird.

Der Code ist ungetestet, sollte aber eine gutes Bild davon geben wie man etwas derartiges implementiert.
User avatar
rzenz
 
Posts: 36
Joined: Mon Dec 12, 2016 1:40 pm
Location: Vienna, Austria


Return to Development (DE)