# ProgressBar/Ladestatus definieren



## FHWS (11. Mai 2018)

Hallo Zusammen,
momentan bin ich dabei meine progressBar mit Leben zu füllen. Kurzer Hintergrund:
Ich habe ein Regal in welchem ich 32 Boxen einlagern kann. Hierfür habe ich eine SQL-Datenbank erstellt in welcher die Boxen aufgelistet sind. Ich möchte nun mit dem Zugriff auf die Datenbank in meiner progessBar den "Belegungsstatus" anzeigen. Sprich ich möchte das in meiner Datenbank die Anzahl der Boxen gezählt wird und mir dann bei z.B. 32 gefundenen Boxen der Status "100" angezeigt wird. Die Verknüpfung zur Datenbank funktioniert. Allerdings stehe ich auf dem Schlauch wie ich das ganze korrekt umsetzten kann. Für Tipps bin ich sehr dankbar! LG

Hier meine bisherige Programmierung

```
// Prozessbar Parameter
       
        progressBar.setStringPainted(true);
        progressBar.setBounds(200, 20, 200, 25);
        progressBar.setEnabled(true);
       
       
        progressBar.setValue((Box_Nr/32)*100);
        String Box_Nr;
            try {
               
               
                    Class.forName("org.mariadb.jdbc.Driver");    //Treiber für ODBC
                    conn = DriverManager.getConnection("jdbc:mariadb://fm-s012mp.fhws.de","Java","1234");
                    System.out.println("Erfolgreich verbunden");   
                   
                    abfrage = conn.createStatement();
                    result = abfrage.executeQuery(
                    "COUNT `Box_Nr`  FROM `lagersystem_test`.`00_hauptdatenbank` ");
                   
                   
                    while (result.next() == true) {
                       
                        String Box_Nr = result.getString("Box_Nr");
                    }       
                   
                    result.close();
                    abfrage.close();
                    conn.close();
                    System.out.println(result);
                }
               
             catch (InterruptedException e) {
                e.printStackTrace();
            }
       
       
       
        add(progressBar);
        progressBar.repaint();
```
:


----------



## CodeGirl (12. Mai 2018)

Was genau macht dir denn Probleme?


----------



## FHWS (12. Mai 2018)

Der Ladestatus zeigt immer 100 % an. Es wird also nicht die korrekte Auslastung angezeigt.
In unten stehender Zeile unterstreicht eclipse mir auch den String... 

```
String Box_Nr = result.getString("Box_Nr");
```


----------



## stg (13. Mai 2018)

```
progressBar.setValue((Box_Nr/32)*100);
String Box_Nr;
```
Hier verwendest du die Variable Box_Nr noch bevor sie initialisiert wurde.
Außerdem teilst du "String durch Integer".



FHWS hat gesagt.:


> In unten stehender Zeile unterstreicht eclipse mir auch den String...
> 
> ```
> String Box_Nr = result.getString("Box_Nr");
> ```


Das liegt daran, da du innerhalb der While-Schleife eine neue Variable "Box_Nr" anlegst, welche die zuvor definierte Variable von weiter oben verdeckt. Nach jedem Schleifendurchlauf schmeißt du diese neue Variable samt Wert, den du zuvor ausgelesen hast, ungenutzt weg. Das ist sicherlich nicht das, was du machen möchtest.
Warum verwendest du überhaupt eine while-Schleife? Dein Query gibt doch genau eine Zeile zurück...


----------



## FHWS (17. Mai 2018)

Das mit der While-Schleife verstehe ich noch, jedoch macht er mir die Abfrage immer noch nicht...
Was muss ich den konkret noch anpassen?

LG


----------



## truesoul (17. Mai 2018)

Hallo. 

Der @stg hat doch die Antwort geliefert. 

Wenn Box_Nr nur eine Zahl sein kann, warum nicht result.getInt ?

Grüße


----------



## FHWS (17. Mai 2018)

Sorry jetzt bin ich raus... Das ist nun mein aktueller Stand:


```
// Prozessbar Parameter
       
        progressBar.setStringPainted(true);
        progressBar.setBounds(200, 20, 200, 25);
        progressBar.setEnabled(true);
       
        add(progressBar);
        progressBar.repaint();
       
   
        float Box_Nr;
            try {
               
               
                    Class.forName("org.mariadb.jdbc.Driver");    //Treiber für ODBC
                    conn = DriverManager.getConnection("jdbc:mariadb://fm-s012mp.fhws.de","Java","wildewalnuss");
                    System.out.println("Erfolgreich verbunden");   
                   
                    abfrage = conn.createStatement();
                    result = abfrage.executeQuery(
                    "COUNT `Box_Nr`  FROM `lagersystem_test`.`00_hauptdatenbank` ");
       
                    while (result.next() == true) {
                       
                        Box_Nr = result.getInt("Box_Nr");
                    }       
                }
               
             catch (InterruptedException e) {
                e.printStackTrace();
            }
       
        progressBar.setValue(((Box_Nr/50)*100));
```


Könnt Ihr mir bitte direkt im Code die Anmerkungen geben, ich glaub sonst komm ich vom Schlauch nicht runter.

LG


----------



## truesoul (17. Mai 2018)

Die Schleife benötigst du nicht. 
Und du könntest den Debugger doch auch verwenden. 
Schaue was Box_Nr für ein Wert hat nach result.getInt()

Wo initialisierst du deine progressBar?


----------



## Neumi5694 (17. Mai 2018)

Wo legst du eigentlich fest, dass 100 der maximale Wert der Progressbar ist?
Fang klein an. Setz die Bar mal manuell ohne Zähler auf 50%. Erst danach denke an die DB.

Dann ist noch eines zu beachten: Es könnte auch einfach so sein, dass dein GUI-Thread blockiert wird. Das lässt sich anhand des Code-Ausschnitts nicht erkennen.
Wenn deine Logik z.b. von einem Button aus aufgerufen wird, dann wird die UI erst dann neu gezeichnet, wenn alles, was beim Klick passieren soll, abgearbeitet wurde. Am Ende hat die Bar natürlich 100% und das ist dann auch das Einzige, was du siehst, da die Zwischenschritte nie gezeichnet wurden.

Wenn ich so was wie eine Fortschrittsanzeige oder ein Echtzeit-Log haben will, dann pack ich den Ablauf immer in einen eigenen Thread.

https://docs.oracle.com/javase/tutorial/uiswing/components/progress.html
Das ist ein ganz anständiges Tutorial mit Beispielprogramm, schau mal rein.


----------



## FHWS (1. Jun 2018)

Hallo Zusammen,

ich bin nun nochmals auf das Problem zurückgekommen. Kurz nochmal was ich eigtl. vor habe. Ich möchte aus meiner Datenbank die Anzahl der Zeilen herauslesen, welche nicht Null sind. Die Anzahl der Zeilen z.B. 20 sollen dann als Ladestatus z.B. 50 % bei insgesamt 40 Zeilen anzeigt werden.
Bekomme jetzt allerdings im letzten Teil beim eigentlichen "Berechnen" des Wertes einen Fehler. Der Fehler ist im Skript markiert. Kann mir einer sagen wo der Fehler liegt?
Dankeee 


```
progressBar.setStringPainted(true);
        progressBar.setBounds(200, 20, 200, 25);
        progressBar.setEnabled(true);
       
        add(progressBar);
        progressBar.repaint();
       
       
        float  Wert;
           
            try {

                  Class.forName("org.mariadb.jdbc.Driver");

                        Connection con = java.sql.DriverManager.getConnection("jdbc:mariadb://fm-s012mp.fhws.de","Java","XXX");

                        Statement s = con.createStatement();

                        ResultSet res;

                        res = s.executeQuery("SELECT COUNT (*) AS anzahl FROM `lagersystem_test`.`00_hauptdatenbank` WHERE Boxinhalt IS NOT NULL" );

                        while (res.next()) {

                              System.out.print(res.getString("anzahl") );
                              Wert = result.getInt("anzahl");
                             
                        }

                  }

                  catch (Exception e) { System.out.println(""+e.getMessage());}

            int prozent = (int) ((Wert/35)*100); // Hier wird der Fehler bei "Wert" angezeigt
           
            progressBar.setValue(prozent);
```


----------



## fhoffmann (1. Jun 2018)

FHWS hat gesagt.:


> // Hier wird der Fehler bei "Wert" angezeigt


Die Fehlermeldung sollte eigentlich verständlich sein. Der Compiler hat Angst, dass "Wert" nie ein Wert zugewiesen wurde.


----------



## Neumi5694 (1. Jun 2018)

ps: Zu deinem ursprünglichen Problem. Innerhalb der Schleife setzt du die Progressbar nicht, du machst das erst ganz zum Schluss, wenn alles erledigt ist oder durch einen Fehler abgebrochen wurde.

Wenn kein Datensatz eingelesen werden konnte, dann hat "Wert" niemals einene Wert.
ps: Variablennamen schreibt man klein.


----------



## FHWS (1. Jun 2018)

un nun nochmal rumprobiert.. wäre mal für einen Tipp mittels Skript sehr dankbar...


----------



## Neumi5694 (6. Jun 2018)

Zeig mal, was du bisher erreicht hast.
Hast du das Ganze schon mal in einen Thread gepackt? Wie gesagt, deine Oberfläche wird erst neu gezeichnet, sobald der GUI-Thread abgelaufen ist. Und wenn du die Daten während des GUI-Threads einliest, dann wird nur das letzte Ergebnis angezeigt.

ps: Ich hab mich beim Lesen deines Codes vertan, bei dem, was ich gesehen hab, liest du ja gar keine Daten ein. Mein Fehler.
Poste doch nochmal, was du bisher hast.


----------



## Neumi5694 (6. Jun 2018)

Nach diesem Schema sollte es gehen.
Warte NICHT auf den Thread mit join(), sonst wird deine Progressbar wieder nicht angzeigt.
Merke: Auch "repaint" wird erst dann ausgeführt, wenn Methode des Buttons oder Menüs abgearbeitet ist.
Man kann da über die EventQue eingreifen, aber ein eigener Thread ist sinnvoller.


```
public static void aButtonWasClicked() {
        displayProgressBarInGUI();
        Thread dbthread = new Thread() {
            @Override
            public void run() {
                lockGUI();
                int nRecordSets = 0;
                setProgressBarTo(0);
                try (Connection con = DriverManager.getConnection("jdbc:mariadb://fm-s012mp.fhws.de", "Java", "XXX");
                        Statement s = con.createStatement();) {
                    try (ResultSet res = s.executeQuery("SELECT COUNT (*) AS anzahl FROM "
                            + "`lagersystem_test`.`00_hauptdatenbank` WHERE Boxinhalt IS NOT NULL")) {
                        if (res.next()) {
                            nRecordSets = res.getInt(1);
                        }
                    }
                    if (nRecordSets <=0) {
                        return;
                    }
                    setProgressBarMaximum(nRecordSets);
                    int counter = 0;
                    setProgressBarTo(counter);
                    try (ResultSet res = s.executeQuery(readDataSqlString)) {
                        while (res.next()) {
                            readData(res);
                            setProgressBarTo(++counter);
                        }
                    }
                } catch (SQLException exp) {
                    //something bad happened. React accordingly
                } finally {
                unLockGUI();
            }
        };
        dbthread.start();
    }
```



Anm: Die Progressbar in diesem Beispiel hat nicht den maximalen Wert 100, sondern den der Anzahl der Datensätze.
Willst du eine Prozentanzeige, dann ist natürlich die Obergrenze stets 100, der Wert wirg gesetzt auf

```
(int)Math.floor(((double)++counter)/nRecordSets))
```


----------



## mihe7 (6. Jun 2018)

Neumi5694 hat gesagt.:


> Anm: Die Progressbar in diesem Beispiel hat nicht den maximalen Wert 100, sondern den der Anzahl der Datensätze.


Ich glaube, er will etwas wesentlich einfacheres. Es soll nicht den Fortschritt des Lesens aus der Datenbank angezeigt werden sondern einfach nur, wie viele seiner Boxen belegt sind.

Anzahl der Boxen gesamt: 
	
	
	
	





```
final String totalCount = "SELECT count(*) FROM `lagersystem_test`.`00_hauptdatenbank`"
```

Anzahl der gefüllten Boxen: 
	
	
	
	





```
final String usedCount = totalCont + " WHERE Boxinhalt IS NOT NULL"
```

Damit

```
int total = get(totalCount);
int used = get(usedCount);
setProgressBarMaximum(total);
setProgressBarTo(used);
```

Update: sehe gerade, dass er den Prozentsatz der belegten Boxen anzeigen will. Dann wäre es natürlich: setProgressBarMaximum(100); setProgressBarTo((int)(used*100)/total);


----------



## Neumi5694 (6. Jun 2018)

Oh je, richtig. da bin ich wohl die ganze Zeit über das Ziel hinausgeschossen.


----------



## FHWS (7. Jun 2018)

Hallo zusammen 
Cool, danke für die Rückmeldungen probiere das heute gleich mal aus!

LG


----------



## FHWS (7. Jun 2018)

Hallo Zusammen,

ich habe jetzt mein Vorhaben etwas abgespeckt. Ich möchte neben meiner GUI mit einer Nebenklasse die Zählung der belegten Boxen durchführen. Die Zählung funktioniert soweit, bekomme für die Variable "anzahl" den richtigen Wert. Die Variable "anzahl" möchte ich nun in meiner GUI lediglich in ein Textfeld reinschreiben, dass da z.B. nur 30 steht mehr nicht. Ich tu mir allerdings grade sehr schwer die Variable aus der Nebenklasse in meine GUI zu bekommen?!?! Stehe da grade völlig neben der Spur... 

Nebenklasse:

```
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

import javax.swing.JLabel;


import java.sql.DriverManager;

public class Count {

   
   
    static Connection conn;
    static Statement eintrag;
    static Statement eintrag2;
    static String ausgabe;
    Statement abfrage;
    int i;
    ResultSet res;
   
   
   
   
    Count() {
       

       
        try {

              Class.forName("org.mariadb.jdbc.Driver");

                    Connection con = java.sql.DriverManager.getConnection("jdbc:mariadb://fm-s012mp.fhws.de","Java","xx");

                    Statement s = con.createStatement();

                    ResultSet res;

                    res = s.executeQuery("SELECT COUNT (*) AS anzahl FROM `lagersystem_test`.`00_hauptdatenbank` WHERE Boxinhalt > '0'" );

                    while (res.next() == true) {

                          System.out.print(res.getString("anzahl") );
                 
                        
                       
                         
                         
                    }

                    res.close();
                    s.close();
                    con.close();

              }

              catch (Exception e) { System.out.println(""+e.getMessage());}

           }

        }
```

Ausschnitt GUI:


```
textPB1 = new JLabel("XXX"); // hier soll die anzahl rein
        textPB1.setBounds(200, 10, 400, 25);
        textPB1.setVisible(true);
        add(textPB1);
```

Danke für Tipps!


----------



## Neumi5694 (11. Jun 2018)

1. Die Klasse Count kriegt ein Feld namens "anzahl" (private int-Klassenvariable + öffentliche getAnzahl()-Methode)
2. Dieser Wert wird dort gesetzt, wo du zur Zeit System.out stehen hast.
3. Den Wert rurfst du dann so ab

```
Count counter = new Count(); //die Variable wird in deinem Code im Konstruktor gesetzt. Falls du daran was änderst, musst du dann hier die entsprechende Methode aufrufen.
label.setText(String.format("%d", counter.getAnzahl())); //machen wir es mal ordentlich, setText("" + counter.getAnzahl()) würde bei so was einfachem natürlich auch funktionieren.
```

Tip: Setze Anzahl bei der Deklaration auf -1 oder einen anderen ungültigen Wert, dann siehst du beim Aufruf von getAnzahl() sofort, ob der Wert überhaupt gesetzt wurde.

ps: Mein Beispiel oben war zwar zu aufwendig, darin siehst du aber, wie du try-with-Resourcen verwendest.
https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
Diese sind ganz praktisch, am Ende des Blocks werden alle damit definierten Resourcen geschlossen, dann brauchst du dich darum nicht selbst zu kümmern.


Und noch was ... in deinem Try Catch gibst du die Fehlermeldung nach System.out aus.
1. Wenn man schon keinen richtige Logger, will dann verwendet man für Fehler System.err
2. Ruf dann auch e.printStackTrace(System.err) auf.
Die Meldung allein ist zum Debuggen selten hilfreich, besonders wenn der Fehler weiter innen passiert.


----------



## FHWS (13. Jun 2018)

Danke für deinen Tipp. Allerdings hänge ich noch an einer Aussage :


> (private int-Klassenvariable + öffentliche getAnzahl()-Methode)



Wie kann der Befehl denn ausgeschrieben aussehen? Danke.
LG


----------



## mihe7 (13. Jun 2018)

Genauso, wie er es geschrieben hat:


```
private int anzahl;
public int getAnzahl() { return anzahl; }
```

EDIT: ich lese gerade, dass er "Klassenvariable" schreibt. Für eine Klassenvariable (static) sehe ich allerdings keinen Grund.


----------



## truesoul (13. Jun 2018)

mihe7 hat gesagt.:


> Genauso, wie er es geschrieben hat:
> 
> 
> ```
> ...



Das ist aber eine Instanzvariable (die womöglich auch gemeint war).

Eine Klassevariable ist z. B 

```
private static int anzahl;
```

Grüße


----------



## mihe7 (13. Jun 2018)

Das war mir hinterher dann auch aufgefallen  Vermutlich sollte das einfach die Abkürzung für "Variable in der Klasse" sein.


----------



## Neumi5694 (13. Jun 2018)

mihe7 hat gesagt.:


> Genauso, wie er es geschrieben hat:
> 
> 
> ```
> ...


Ja, mein Fehler. Instanzvariable wäre richtig.


----------



## FHWS (13. Jun 2018)

Hallo Leute.
Danke für eure Hinweise. Ich glaube ich stehe jedoch bei dem Thema total auf dem Schlauch... Wenn ich in der Klasse Count nun bei "public int anzahl;" einen Wert von -1 beispielsweise definiere dann überträgt er mir das auch in die GUI.
Lasse ich die -1 weg nimmt er sich die ausgezählte Variabel jedoch nicht. In der GUI steht dann eine 0. Das Problem liegt also bei der Übernahme der ausgezählten variablen "anzahl"....


```
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

import javax.swing.JLabel;


import java.sql.DriverManager;

public class Count {

  
  
    static Connection conn;
    static Statement eintrag;
    static Statement eintrag2;
    static JLabel textPB1;
    static String ausgabe;
    Statement abfrage;
    int i;
    ResultSet res;
    private int num;
    public int anzahl;
    public int getAnzahl() { return anzahl; }
  
  
  
    Count() {
      

        try {

              Class.forName("org.mariadb.jdbc.Driver");

                    Connection con = java.sql.DriverManager.getConnection("jdbc:mariadb://fm-s012mp.fhws.de","Java","wildewalnuss");

                    Statement s = con.createStatement();

                    ResultSet res;

                    res = s.executeQuery("SELECT COUNT (*) AS anzahl FROM `lagersystem_test`.`00_hauptdatenbank` WHERE Boxinhalt > '0'" );

                    while (res.next() ) {
                      
                             
                         System.out.print(res.getString("anzahl") );
                         
                         GUI_Lager.setTextExternally(res.getString("anzahl"));
                                             
                    }
                  
                    res.close();
                    s.close();
                    con.close();

              }

              catch (Exception e) { System.out.println(""+e.getMessage());}
      
        

      
           }
  

        }
```
Findet jemand den Fehler ? Ich hab mittlerweile Tomaten auf den Augen...


----------



## Neumi5694 (13. Jun 2018)

Ich frag mal so ... an wlchem Punkt denkst du denn, dass du die Variable setzen solltest? In deinem Code machst du das nämlich nicht.
Deshalb hab ich dir den Tip mit -1 ja geschrieben, damit du genau diesen Fall erkennst: Du setzt die Variable nicht ....


----------



## mihe7 (13. Jun 2018)

Hier mal das Prinzip, wie es vorgeschlagen wurde. Deinen Konstruktor habe ich mal durch etwas einfaches ersetzt:


```
import java.awt.BorderLayout;
import javax.swing.*;

class Count {
    private int anzahl;

    public Count() {
        anzahl = (int)(Math.random() * 30);
    }

    public int getAnzahl() {
        return anzahl;
    }
}

public class Test implements Runnable {

    public void run() {
        JLabel anzahlLabel = new JLabel(" ");
        JButton button = new JButton("Abrufen");
        button.addActionListener(e -> {
            int anzahl = new Count().getAnzahl();
            anzahlLabel.setText(String.format("Es gibt %d benutzte Boxen", anzahl));
        });

        JFrame frame = new JFrame("Test");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(anzahlLabel, BorderLayout.NORTH);
        frame.add(button, BorderLayout.SOUTH);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Test());
    }

}
```


----------



## Neumi5694 (13. Jun 2018)

FHWS hat gesagt.:


> Lasse ich die -1 weg nimmt er sich die ausgezählte Variabel jedoch nicht. In der GUI steht dann eine 0. Das Problem liegt also bei der Übernahme der ausgezählten variablen "anzahl"....



ps: Nein, tut's nicht. 0 ist der Wert, den die Variable hat, wenn du sie nicht mit -1 initialisiert und auch sonst nirgends setzt. Die Übernahme funktioniert tadellos. Nur muss zuerst mal was drinstehen.


----------

