2 ComboBox(en)

M

maGG

Bekanntes Mitglied
Ich habe 2 ComboBox(en) und in beide wird mit einer fill-Methode Labels, mit Strings, aus einer SQL Datenbank geladen. Genauer gesagt werden mit "SELECT *" alle Spalten ausgewählt, aber nur die LABEL(s) aus entsprechender Spalte als String Werte in die ComboBox(en) geladen.

Jetzt möchte ich folgendes errreichen: Wenn man in der ersten ComboBox ein Wert auswählt, der nicht dem ersten entspricht ("Bitte auswählen"), dann soll die andere ComboBox auf den ersten Wert ("Bitte auswählen") springen. Das Ganze hat den Hintergrund, dass man nicht in beiden ComboBox(en) einen Wert auswählen soll, da beide Boxen die selben Variablen mit Werten belegen. Im nicht Sehbaren ist das egal, da die Werte vom letzten Action Performed einfach überschrieben werden. Ich möchte jetzt das Ganze visuell unterstützen, so dass der Nutzer ganz klar sehen kann was die zu letzt gesetzte ComboBox war.

Also schematisch: Wähle ich in ComboBox 1 etwas aus, was nicht dem Index 0 entspricht, dann soll bei ComboBox 2 der Index auf 0 gesetzt werden und andersrum. Das führt dazu das man nur einen Wert in beiden ComboBox(en) gleichzeitig auswählen kann - und genau so will ich es.

Ohne SQL und Datenbank Anbindung geht das ganz leicht, mit kommen bei mir jedoch Fehler...

.setSelectedIndex(0); führt dazu, dass die Datenbank gelockt wird.
.setModel("Bitte auswählen"); führt zu dem Fehler: String cannot be converted to ComboBoxModel<String>

Wie kann man das möglichst elegant lösen? Bzw. habt ihr mich verstanden? :D
 
mihe7

mihe7

Top Contributor
Wenn beim Auswahl eines Wertes aus einer ComboBox die DB gesperrt wird, ist etwas grundlegend falsch. Recht viel mehr kann man ohne Details nicht dazu sagen.
 
M

maGG

Bekanntes Mitglied
Danke für deine Antwort. Das ist leider nicht ganz korrekt. Wenn man einen Wert in der ComboBox auswählt entsteht kein Fehler. Nur bei den oben genannten zwei Beispielen. ;)
 
mihe7

mihe7

Top Contributor
Gut, mal anders: warum und was passiert denn auf der DB, wenn Du in der ComboBox etwas auswählst?
 
M

maGG

Bekanntes Mitglied
In der Datenbank sollte eigentlich nix verändert werden, lediglich Werte aus der Datenbank in GUI geladen werden. Wenn man einen Wert in der ComboBox setzt, dann werden Attribute gesetzt (benutze sqlitejdbc sowie rs2xml):
Java:
    private void jComboBoxFilialenDeutschlandActionPerformed(java.awt.event.ActionEvent evt) {                                                             
        try{
            int row = jComboBoxFilialenDeutschland.getSelectedIndex();
            String sql = "SELECT * FROM Filialen_Deutschland WHERE id='" + row + "' ";
            pst = conn.prepareStatement(sql);
            rs = pst.executeQuery();
                strasze = rs.getString("STRASZE");
                plzort = rs.getString("PLZ_ORT");
                ort = rs.getString("ORT");
                telLaendercode = "" + rs.getInt("TEL_LAND");
                telStartInt = "" + rs.getInt("TEL_ANFANG_INT");
                telStartGer = rs.getString("TEL_ANFANG_TXT");
                telEndDefault = "" + rs.getInt("TEL_ENDE_DEFAULT");
                faxStart = rs.getString("FAX_ANFANG_TXT");
                faxEndDefault = rs.getString("FAX_ENDE_TXT");
                Preview();
                Testpreview();
                //jComboBoxFilialenAusland.setSelectedIndex(0);
                //jComboBoxFilialenAusland.setModel("Bitte auswählen");
        }catch(Exception e){
            e.printStackTrace();
            JOptionPane.showMessageDialog(null, e);
        }finally{
            try{
                rs.close();
                pst.close();
            }catch(SQLException e){
                e.printStackTrace();
                JOptionPane.showMessageDialog(null, e);
            }
        }
    }
 
mihe7

mihe7

Top Contributor
Hier findet keine saubere Trennung zwischen DB und UI statt. Du solltest die DB separat behandeln (s. z. B. Repository-Pattern). Aktuell verschachtelst Du ggf. mehrere SQL-Abfragen, d. h. Du hast mehrere Cursor gleichzeitig offen. Das kann zu Problemen führen.

Als Quick & Dirty-Lösungsansatz kannst Du den DB-Part in eine separate Methode auslagern. Den folgende Code bitte als Pseudocode verstehen (ich habe das nur hier im Forum editiert, kann sein, dass er nicht übersetzt wird):
Java:
    private void jComboBoxFilialenDeutschlandActionPerformed(java.awt.event.ActionEvent evt) {                                                            
        int row = jComboBoxFilialenDeutschland.getSelectedIndex();
        try {
            loadGermanBranch(row);
            Preview();
            Testpreview();
            jComboBoxFilialenAusland.setSelectedIndex(0);
        }catch(SQLException e){
            e.printStackTrace();
            JOptionPane.showMessageDialog(null, e);
            return false;
        }
    }
   
    private void loadGermanBranch(int row) throws SQLException {
        String sql = "SELECT * FROM Filialen_Deutschland WHERE id=?";
        try(pst = conn.prepareStatement(sql)) {
            pst.setInt(1, row);
            try(rs = pst.executeQuery()) {
                strasze = rs.getString("STRASZE");
                plzort = rs.getString("PLZ_ORT");
                ort = rs.getString("ORT");
                telLaendercode = "" + rs.getInt("TEL_LAND");
                telStartInt = "" + rs.getInt("TEL_ANFANG_INT");
                telStartGer = rs.getString("TEL_ANFANG_TXT");
                telEndDefault = "" + rs.getInt("TEL_ENDE_DEFAULT");
                faxStart = rs.getString("FAX_ANFANG_TXT");
                faxEndDefault = rs.getString("FAX_ENDE_TXT");
            }
        }
    }
Analog für die andere ComboBox. Noch ein paar grundsätzliche Anmerkungen:
1. Baue Parameter in SQL-Strings nie manuell ein. Verwende die setXXX-Methoden von PreparedStatement.
2. Verwende try-with-resources (die Ressourcen werden dann automatisch geschlossen)
3. Verlass Dich nicht darauf, dass Ergebnisse vorhanden sind (habe ich im Code jetzt nicht berücksichtigt). Die row könnte -1 sein und zwischen dem Laden der Werte der ComboBox und der Auswahl durch den Benutzer liegt genügend Zeit, dass jemand ausgerechnet die Filiale löscht, die der Benutzer dann auswählt.
 
M

maGG

Bekanntes Mitglied
Ok, das verstehe ich nicht ganz; muss man das so trennen? Ich habe einige SQL Methode, zum Befüllen, editieren, etc. muss man das immer trennen? Weil das würde enorm viel mehr Zeilen Code bedeuten :O
 
E

Elenteria

Bekanntes Mitglied
Muss man nicht, aber wenn es Sauber und leichter erweiterbar sein soll tust du gut daran das zu Trennen.
 
M

maGG

Bekanntes Mitglied
1. Baue Parameter in SQL-Strings nie manuell ein. Verwende die setXXX-Methoden von PreparedStatement.
2. Verwende try-with-resources (die Ressourcen werden dann automatisch geschlossen)
3. Verlass Dich nicht darauf, dass Ergebnisse vorhanden sind (habe ich im Code jetzt nicht berücksichtigt). Die row könnte -1 sein und zwischen dem Laden der Werte der ComboBox und der Auswahl durch den Benutzer liegt genügend Zeit, dass jemand ausgerechnet die Filiale löscht, die der Benutzer dann auswählt.
habe ich das mit finally -> rs.close() und pst.close() nicht schon sichergestellt? Also das es geschlossen wird meine ich. Der Code ist von mir zusammengesetzt; habe leider kaum Beispiele dazu im Internet gefunden wie man das perfekt machen kann. Auch meine anderen SQL Methode sehen ähnlich aus und wären dann vermutlich nicht optimal, hmm ...
 
mihe7

mihe7

Top Contributor
habe ich das mit finally -> rs.close() und pst.close() nicht schon sichergestellt?
Jein. Man kann das mit finally machen, das war in Java 6 Standard (ging nicht anders). Der Code ist aber hässlich, weil Du überall finally-Blöcke brauchst, die allerdings etwas anders aussehen müssten als Deiner. Wenn bei Dir z. B. eine Exception in prepareStatement aufritt, ist Dein ResultSet (normalerweise, ich sehe bei Dir gar keine Deklaration) null, was im finally-Block bei rs.close() zu einer NullPointerException führt. Seinerzeit habe ich (wie vermutlich viele andere auch) dafür Utility-Methoden geschrieben, die in etwa so aussahen:
Java:
public static void close(ResultSet rs, Statement stmt) {
    if (rs != null) {
        try { rs.close(); } catch (SQLException ex) { /* hier ggf. Warnung loggen. */ }
    }
    if (stmt != null) {
        try { stmt.close(); } catch (SQLException ex) { /* hier ggf. Warnung loggen. */ }
    }
}
Die Methode wure dann im finally-Block verwendet close(rs, stmt);. Seit Java 7 braucht man den ganzen Käse Dank try-with-resources nicht mehr.

Ok, das verstehe ich nicht ganz; muss man das so trennen?
Müssen muss man gar nichts... Im konkreten Fall sorgt die Trennung dafür, dass das SQL-Gedöns abgeschlossen ist, bevor irgend etwas anderes passiert. Wenn Du Dir jetzt den actionListener ansiehst, fällt Dir viel schneller auf, dass Du Events hin und her feuerst, weil der row-Index nicht abgeprüft wird :) (Du musst am Anfang noch prüfen, ob der row-Index 0 ist).
 
M

maGG

Bekanntes Mitglied
Oh man :( hatte eigentlich gedachte das wäre leichter :O
habe gerade mal deine Anpassung ausprobiert und bei mir kommen folgende Fehler:
Code:
try(pst = conn.prepareStatement(sql)){ // hier kommt bei mir "variables in try-with-resources not supported in -source 1.8"
try(rs = pst.executeQuery()){ // hier kommt "the try-with-resources resource must either be a variable declaration or an expression
denoting a reference to a final or effectively final variable"
 
mrBrown

mrBrown

Super-Moderator
Mitarbeiter
Oh man :( hatte eigentlich gedachte das wäre leichter :O
habe gerade mal deine Anpassung ausprobiert und bei mir kommen folgende Fehler:
Code:
try(pst = conn.prepareStatement(sql)){ // hier kommt bei mir "variables in try-with-resources not supported in -source 1.8"
try(rs = pst.executeQuery()){ // hier kommt "the try-with-resources resource must either be a variable declaration or an expression
denoting a reference to a final or effectively final variable"
Stell deine IDE auf Java 8 und deklarier die Variablen dort, wo du sie auch initialisierst ;)
 
mihe7

mihe7

Top Contributor
Ja, da fehlen die Deklarationen:
Java:
        try(PreparedStatement pst = conn.prepareStatement(sql)) {
            pst.setInt(1, row);
            try(ResultSet rs = pst.executeQuery()) {
 
mihe7

mihe7

Top Contributor
Oh man :( hatte eigentlich gedachte das wäre leichter :O
Software hat das Problem, inhärent komplex zu sein. Als wäre das nicht genug, soll sich Software im Gegensatz zu anderen Gütern möglichst einfach an neue bzw. veränderte Anforderungen anpassen lassen. Um das in den Griff zu bekommen, haben sich über die Zeit verschiedene Herangehensweisen, Paradigmen, Pattern etc. herausgebildet. Und nach wie vor muss man feststellen, dass es kein Patentrezept gibt. Kurz: schnell, gut, kostengünstig - such Dir zwei aus.
 
M

maGG

Bekanntes Mitglied
Ja das ist leider richtig und es kann sehr frustrierend sein das anderen Menschen verständlich zu machen, die nur die Oberfläche sehen und sich denken das wäre so leicht :D

Also mit deinen Code habe ich es geschafft die Methode auf zwei zu trennen. Jedoch habe ich jetzt gerade ein anderes Problem:

Java:
        private void loadTitel(int row) throws SQLException{
        String sql = "SELECT * FROM Titel WHERE id=?";
        try(PreparedStatement pst = conn.prepareStatement(sql)){
            pst.setInt(1, row);
            try(ResultSet rs = pst.executeQuery()){
            String label = rs.getString("LABEL");
            boolean infront = rs.getBoolean("VORNE");
            if(infront = false){
                titelvorn = label;
                titelhinten = "";
            }else{
                titelhinten = label;
                titelvorn = "";
            }
            }
        }
        }
  private void jComboBoxTitelblaActionPerformed(java.awt.event.ActionEvent evt) {
        int row = jComboBoxTitelbla.getSelectedIndex();
        try{
            loadTitel(row);
            Testpreview();
        }catch(SQLException e){
            e.printStackTrace();
            JOptionPane.showMessageDialog(null, e);
            //return false; // wozu return false???
        }
}
wie man glaub unschwer erkennen kann soll die Variable titelvorn gesetzt werden wenn infront true ist und wenn es false ist soll titelhinten gesetzt werden. Leider zeigt er bei der if-Verzweigung alle Titel vorn an wenn ich if(infront = true)... schreibe und alle hinten wenn ich if(infront = false)... schreibe ... ist stehe etwas auf den Schlauch gerade, HÄÄÄ :'(
 
E

Elenteria

Bekanntes Mitglied
probiers mal mit == statt = im if-statement. Mit == vergleichst du Dinge, mit = weißt du sie zu
 
M

maGG

Bekanntes Mitglied
Oh man, ja das war dumm :D
hmm geht aber leider immer noch nicht; es zeigt nur eine Richung an, er belegt nur titelvorn (egal bei welchen Wert). Eigentlich müsste titelvorn zu mindest mal irgendwann leer sein.

Danke übrigens nochmal für eure Hilfe! :)
 
M

maGG

Bekanntes Mitglied
Hab noch ein Fehler entdeckt: Wenn ich auf das erste Item der ComboBox klicke kommt "java.sql.Exception: REsultSet closed"
 
M

maGG

Bekanntes Mitglied
OK, habe den Fehler behoben; der Logikfehler bei der Verzweigung bleibt jedoch. Also die Attribute titelvorn und titelhinten werden nicht richtig gesetzt bzw. es wird nur titelhinten mit Werten belegt.
Java:
        private void loadTitel(int row) throws SQLException{
            String sql = "SELECT * FROM Titel WHERE id=?";
            try(PreparedStatement pst = conn.prepareStatement(sql)){
                pst.setInt(1, row);
                try(ResultSet rs = pst.executeQuery()){
                    if(row != 0){
                        String label = rs.getString("LABEL");
                        boolean infront = rs.getBoolean("VORNE");
                        if(infront == true){
                            titelvorn = label;
                            titelhinten = "";
                        }else{
                            titelvorn = "";
                            titelhinten = label;
                        }
                    }
                }
            }
        }
SQL:
CREATE TABLE Titel (
    id    INTEGER PRIMARY KEY AUTOINCREMENT,
    LABEL TEXT,
    VORNE BOOLEAN
);
So kompliziert kann das Ganze doch nicht sein ... o_O aber es funktioniert leider noch nicht, seht ihr direkt etwas falsches?
 
Zuletzt bearbeitet:
mrBrown

mrBrown

Super-Moderator
Mitarbeiter
Prüft, ob im ResultSet eine weitere Zeile verfügbar ist, und "springt" zu dieser.
Nach Ausführen der Query zeigt das ResultSet noch auf kein Ergebnis (es könnte ja auch leer sein), mit next zeigt es dann auf die erste Zeile (und mit weiteren Aufrufen dann auf die danach.)
 
mihe7

mihe7

Top Contributor
So kompliziert kann das Ganze doch nicht sein ... o_O aber es funktioniert leider noch nicht, seht ihr direkt etwas falsches?
LOL, ne kompliziert ist das alles nicht. Die Prüfung auf row == 0 sollte ganz am Anfang stehen (s. Kommentar #11, ggf. besser noch in der Methode, die loadTitel aufruft) und nach dem Ausführen der Abfrage sollte man prüfen, ob die Abfrage überhaupt ein Ergebnis liefert (s. Kommentar #6, Nummer 3):
Java:
        private void loadTitel(int row) throws SQLException{
            if (row == 0) {
                return;
            }
            String sql = "SELECT * FROM Titel WHERE id=?";
            try(PreparedStatement pst = conn.prepareStatement(sql)){
                pst.setInt(1, row);
                try(ResultSet rs = pst.executeQuery()){
                    if(rs.next()){
                        String label = rs.getString("LABEL");
                        boolean infront = rs.getBoolean("VORNE");
                        if(infront){
                            titelvorn = label;
                            titelhinten = "";
                        }else{
                            titelvorn = "";
                            titelhinten = label;
                        }
                    }
                }
            }
        }
 
M

maGG

Bekanntes Mitglied
Vielen lieben Dank @mihe7 und euch anderen für die Hilfe. Es sieht bei mir jetzt so aus:

Java:
    private void jComboBoxTitelblaActionPerformed(java.awt.event.ActionEvent evt) {                                                 
        int row = jComboBoxTitelbla.getSelectedIndex();
        if (row == 0) {           
            titelvorn = "";
            titelhinten = "";
            Testpreview();
            return;
        }           
        try{
            loadTitel(row);
            Testpreview();
        }catch(SQLException e){
            e.printStackTrace();
            JOptionPane.showMessageDialog(null, e);
            //return false;
        }

        private void loadTitel(int row) throws SQLException{           
            String sql = "SELECT * FROM Titel WHERE id=?";
            try(PreparedStatement pst = conn.prepareStatement(sql)){
                pst.setInt(1, row);
                try(ResultSet rs = pst.executeQuery()){
                    if(rs.next()){
                        String label = rs.getString("LABEL");
                        boolean infront = rs.getBoolean("VORNE");
                        if(infront){
                            titelvorn = label + " ";
                            titelhinten = "";
                        }else{
                            titelvorn = "";
                            titelhinten = ", " + label;
                        }
                    }
                }
            }
        }
Ist es jetzt richtig so?
Ich verstehe ehrlich gesat nicht so ganz was das "return;" und "return false" genau macht o_O
Also return ist ja eine Rückgabe, aber da ist jetzt gar keine Variable mit drin?
 
mihe7

mihe7

Top Contributor
Das sieht mal nicht verkehrt aus. Das return sorgt dafür, dass an der Stelle der Methodenaufruf (die Methode muss ja von irgendwo aus aufgerufen worden sein) beendet wird. Einen Rückgabewert gibt es hier nicht, weil die Methode mit dem Rückgabetyp "void", also "nichts", deklariert wurde. Ein "return false" wäre dem entsprechend falsch, da die Methode nicht mit dem Rückgabetyp "boolean" deklariert wurde.

Konkret: der Listener prüft ab, ob row == 0 gilt, falls ja, werden testvorn und testhinten gesetzt und die die Methode Testpreview() wird aufgerufen. Dann wird die Ausführung der Listener-Methode per return beendet. Ist row != 0, dann werden loadTitel(row) und Testpreview() aufgerufen. Tritt dabei eine SQLException auf, wird der betreffende catch-Block ausgeführt (Stacktrace geschrieben, JOptionPane angezeigt).
 
M

maGG

Bekanntes Mitglied
Ok, cool Dankschön @mihe7!

Ich hab leider noch ein paar weitere Methoden, die ich wohl optimieren sollte, z.B. diese hier:

Java:
        private void fillComboBoxFilialenDeutschland(){
            try{
                String sql = "SELECT * FROM Filialen_Deutschland";
                pst = conn.prepareStatement(sql);
                rs = pst.executeQuery();
                //jComboBoxSchablonen.addItem(sql);
                while(rs.next()){
                    String label = rs.getString("LABEL");
                    jComboBoxFilialenDeutschland.addItem(label);
                }
            }catch(Exception e){
                e.printStackTrace();
            }finally{
                try{
                    rs.close();
                    pst.close();
                    //conn.close();
                }catch(SQLException e){
                    e.printStackTrace();
                    JOptionPane.showMessageDialog(null, e);
                }
        }
        }
Ich habe das mal versucht, mit euren Vorschlägen anzupassen:
Java:
        private void fillComboBoxGermanBranches() throws SQLException{
            String sql = "SELECT * FROM Filialen_Deutschland";
            try(PreparedStatement pst = conn.prepareStatement(sql)){
                try(ResultSet rs = pst.executeQuery()){
                    while(rs.next()){
                        String label = rs.getString("LABEL");
                        jComboBoxFilialenDeutschland.addItem(label);
                    }
                }
            }
        }
Könnte das so in etwa funktionieren? Ich hätte gerne eine Fehlerausgabe mit JOptionPane, wo würde ich das reinschreiben?

Update: Kommen folgende Fehler:
Code:
C:\...\GUI.java:130: error: unreported exception SQLException; must be caught or declared to be thrown
        fillComboBoxGermanBranches();
1 error
C:\...\nbproject\build-impl.xml:953: The following error occurred while executing this line:
C:\...\nbproject\build-impl.xml:270: Compile failed; see the compiler error output for details.
BUILD FAILED (total time: 11 seconds)
 
Zuletzt bearbeitet:
M

maGG

Bekanntes Mitglied
s. Kommentar #6 :)

EDIT: damit ich Dich nicht auf die falsche Spur führe, sollte ich noch klarstellen, dass es nur um das try-catch im ActionListener geht.
Danke für deine Antwort!

Ok habe es jetzt um das Aufruf-Statement geschrieben:
Java:
        try {
            fillComboBoxGermanBranches();
        } catch (SQLException e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(null, e);
        }
Das heißt natürlich, dass ich jetzt jedes mal ein Try-Catch-Block brauche, wenn ich die Methode aufrufe. Ich rufe die Methode u.a. beim Start im Standardkonstruktor auf. Ist das das die eleganteste Lösung oder kann ich das auch in der Methode selbst einbetten, oder macht man das nicht? :)
 
mihe7

mihe7

Top Contributor
In diese Methode bettet man das nicht ein, wenn man sauber trennen will (in dem Fall ruft man dort auch keine Methoden der JComboBox auf...) Und eigentlich sollte die Methode in eine eigene Klasse.

Die Methode fillComboBoxGermanBranches müsste eigentlich loadGermanBranches heißen und eine Liste zurückgeben, z. B.

Java:
        private List<String> loadGermanBranches() throws SQLException{
            String sql = "SELECT * FROM Filialen_Deutschland";
            try(PreparedStatement pst = conn.prepareStatement(sql)){
                try(ResultSet rs = pst.executeQuery()){
                    List<String> result = new ArrayList<>();
                    while(rs.next()){
                        result.add(rs.getString("LABEL"));
                    }
                    return result;
                }
            }
        }

Wie gesagt, eigentlich lagert man diesen Code in separate Klassen aus. Die fillComboBoxGermanBranches-Methode könnte dann so aussehen:
Java:
    private void fillComboBoxGermanBranches() {
        try {
            for (String label : loadGermanBranches()) {
                jComboBoxFilialenDeutschland.addItem(label);
            }
        } catch (SQLException e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(null, e);
        }
    }

Du kannst auch hergehen und in der load-Methode die SQLException abfangen und durch eine unchecked Exception ersetzen, dann fallen die try-catch-Blöcke ganz weg. Dann müsstest Du aber beim Thread einen Exception-Handler für nicht abgefangene Exceptions registrieren.
 
M

maGG

Bekanntes Mitglied
Ah ok, man lernt nie aus :) bin kein richtiger Informatiker, also hab interdisziplinär Grundlagen der Ingenieurinformatik (Java) gehört und Datenbanken für Ingenieuranwendungen (CAD, Revit, C# mit Visual Basic und SQL mit Java), aber nach zwei Module und eine Hand voll von Hausübungen befähigt einen das längst noch nicht sowas mal locker von der Hand runterzuschreiben ;'D
Für mein Aushilfsjob hier wird eh nix erwartet, mache das alles freiwillig.

Hmm deiner Variante wäre wohl besser, evtl. mache ich das noch am Ende, wenn die Hauptfunktionen des Programms alle da sind.
 
M

maGG

Bekanntes Mitglied
Hmm neues Problem :D

Der Code bei #26 hat einen Nachteil: Wenn ich die Methode fillComboBoxGermanBranches() mehrmals aufrufe werden die Einträge der ComboBox immer größer und ich habe Dubletten. Wie kann ich das elegant vermeiden?
Habe es mit .removeAllItems() probiert, aber das funktioniert leider nicht richtig. Ich will ja nicht alle Einträge löschen, z.B. der erste "Bitte auswählen" soll bleiben. Habt ihr eine Idee? :)
 
mrBrown

mrBrown

Super-Moderator
Mitarbeiter
Hmm neues Problem :D

Der Code bei #26 hat einen Nachteil: Wenn ich die Methode fillComboBoxGermanBranches() mehrmals aufrufe werden die Einträge der ComboBox immer größer und ich habe Dubletten. Wie kann ich das elegant vermeiden?
Habe es mit .removeAllItems() probiert, aber das funktioniert leider nicht richtig. Ich will ja nicht alle Einträge löschen, z.B. der erste "Bitte auswählen" soll bleiben. Habt ihr eine Idee? :)
Die Methode nicht mehrmals aufrufen? :p

Warum willst du die Methode denn mehrmals aufrufen? (Falls das schon irgendwo steht hab ich's überlesen...)
 
M

maGG

Bekanntes Mitglied
Warum willst du die Methode denn mehrmals aufrufen? (Falls das schon irgendwo steht hab ich's überlesen...)
Also wenn man das Programm startet sollen die ComboBoxen alle gefüllt werden. Dann gibt es aber ein zweites Fenster, welches man öffnen kann und wo man die Datenbank im Programm selbst in Tabellen-form editeren kann - hat man das getan und z.B. einen neuen Eintrag hinzugefügt, dann kehrt man auf das Hauptfenster zurück. Beim Zurückkehren soll das Zweitfenster geschlossen werden und alle Comboboxen neu befüllt werden, denn schließlich könnte man an der Datenbank etwas geändert haben. Natürlich könnte ich auch einfach das Programm neustarten, aber ich denke man kann das auch so irgendwie lösen.

Hmm macht das für dich Sinn? :D
 
mrBrown

mrBrown

Super-Moderator
Mitarbeiter
Entweder alle entfernen, und dann alle inklusive des ersten Eintrags neu hinzufügen, oder ein eigenes ComboBoxModel nutzen, welches das Updaten der Einträge unterstützt und dabei den ersten immer erhält.
 
M

maGG

Bekanntes Mitglied
Heyho, habe ein neues Problem :D
(Habe das versucht aufzuteilen, aber irgendetwas funktioniert noch nicht, also die Vorschau Funktion geht, aber das Updaten der Datenbank leider noch nicht)

Seht ihr einen Fehler? Vielen Dank! :)

Java:
    private void jButtonUpdateA1ActionPerformed(java.awt.event.ActionEvent evt) {                                               
        int row = Integer.parseInt(jTextFieldF1.getText());
        String label = jTextFieldF2.getText();
        String strasze = jTextFieldF3.getText();
        String plzort = jTextFieldF4.getText();
        String ort = jTextFieldF5.getText();
        int telland = Integer.parseInt(jTextFieldF6.getText());
        long telanfangint = Long.parseLong(jTextFieldF7.getText());
        String telanfangtxt = jTextFieldF8.getText();
        String telendedefault = jTextFieldF9.getText();
        String faxanfangtxt = jTextFieldF10.getText();
        String faxendetxt = jTextFieldF11.getText();
        if  (jTextFieldF1.getText().equals("") || label.equals("") || strasze.equals("")
            || plzort.equals("") || ort.equals("") || jTextFieldF6.getText().equals("")
            || jTextFieldF7.getText().equals("") || telanfangtxt.equals("") || telendedefault.equals("")
            || faxanfangtxt.equals("") || faxendetxt.equals("")){
            JOptionPane.showMessageDialog(null, "Fehler: Bitte notwendige Parameter setzen");
        }else {           
            try{
                updateTableGermanBranches(row, label, strasze, plzort, ort, telland, telanfangint, telanfangtxt, telendedefault, faxanfangtxt, faxendetxt);
                viewTableGermanBranches();
                JOptionPane.showMessageDialog(null, "Filiale aktualisiert");
            }catch(SQLException e){
                e.printStackTrace();
                JOptionPane.showMessageDialog(null, e);
            }
        }
    }
Java:
    public void updateTableGermanBranches(int row, String label, String strasze, String plzort, String ort, int telland, long telanfangint, String telanfangtxt, String telendedefault, String faxanfangtxt, String faxendetxt) throws SQLException{
        String sql = "UPDATE Filialen_Deutschland SET id=?, LABEL=?, STRASZE=?, PLZ_ORT=?, ORT=?,TEL_LAND=?, TEL_ANFANG_INT=?,"
                        + " TEL_ANFANG_TXT=?, TEL_ENDE_DEFAULT=?, FAX_ANFANG_TXT=?, FAX_ENDE_TXT=? WHERE id=?";
        try (PreparedStatement pst = conn.prepareStatement(sql)) {
            try (ResultSet rs = pst.executeQuery()) {
                if (rs.next()) {
                    pst.setInt(1, row); // id
                    pst.setString(2, label); //LABEL
                    pst.setString(3, strasze); //STRASZE
                    pst.setString(4, plzort); //PLZ_ORT
                    pst.setString(5, ort); //ORT
                    pst.setInt(6, telland); //TEL_LAND
                    pst.setLong(7, telanfangint); //TEL_ANFANG_INT
                    pst.setString(8, telanfangtxt); //TEL_ANFANG_TXT
                    if (telendedefault.equals("")) {
                        pst.setObject(9, null);
                    } else {
                        pst.setInt(9, Integer.parseInt(telendedefault)); //TEL_ENDE_DEFAULT
                    }
                    pst.setString(10, faxanfangtxt); //FAX_ANFANG_TXT
                    if (faxendetxt.equals("")) {
                        pst.setObject(11, null);
                    } else {
                        pst.setString(11, faxendetxt); //FAX_ENDE_TXT
                    }
                    pst.setInt(12, row); // id (doppelt)
                    pst.executeUpdate();                               
                }
            }
        }   
    }
Java:
    public void viewTableGermanBranches() throws SQLException{
         String sql = "SELECT * FROM Filialen_Deutschland";
        try (PreparedStatement pst = conn.prepareStatement(sql)) {
            try (ResultSet rs = pst.executeQuery()) {
                if (rs.next()) {
                    jTableFilialen_Deutschland.setModel(DbUtils.resultSetToTableModel(rs));
                }
            }
        }   
    }
Code:
java.sql.SQLException: Query does not return results
    at org.sqlite.jdbc3.JDBC3PreparedStatement.executeQuery(JDBC3PreparedStatement.java:68)
    at signatur.GUI.updateTableGermanBranches(GUI.java:792)
    at signatur.GUI.jButtonUpdateA1ActionPerformed(GUI.java:5154)
    at signatur.GUI.access$1000(GUI.java:60)
    at signatur.GUI$11.actionPerformed(GUI.java:1493)
 
mrBrown

mrBrown

Super-Moderator
Mitarbeiter
WTF.
bzw: WTF?!?!

Java:
    public void updateTableGermanBranches(int row, String label, String strasze, String plzort, String ort, int telland, long telanfangint, String telanfangtxt, String telendedefault, String faxanfangtxt, String faxendetxt) throws SQLException{
        String sql = "UPDATE Filialen_Deutschland SET id=?, LABEL=?, STRASZE=?, PLZ_ORT=?, ORT=?,TEL_LAND=?, TEL_ANFANG_INT=?,"
                        + " TEL_ANFANG_TXT=?, TEL_ENDE_DEFAULT=?, FAX_ANFANG_TXT=?, FAX_ENDE_TXT=? WHERE id=?";
        try (PreparedStatement pst = conn.prepareStatement(sql)) {
            try (ResultSet rs = pst.executeQuery()) {
                if (rs.next()) {
                    pst.setInt(1, row); // id
                    pst.setString(2, label); //LABEL
                    pst.setString(3, strasze); //STRASZE
                    pst.setString(4, plzort); //PLZ_ORT
                    pst.setString(5, ort); //ORT
                    pst.setInt(6, telland); //TEL_LAND
                    pst.setLong(7, telanfangint); //TEL_ANFANG_INT
                    pst.setString(8, telanfangtxt); //TEL_ANFANG_TXT
                    if (telendedefault.equals("")) {
                        pst.setObject(9, null);
                    } else {
                        pst.setInt(9, Integer.parseInt(telendedefault)); //TEL_ENDE_DEFAULT
                    }
                    pst.setString(10, faxanfangtxt); //FAX_ANFANG_TXT
                    if (faxendetxt.equals("")) {
                        pst.setObject(11, null);
                    } else {
                        pst.setString(11, faxendetxt); //FAX_ENDE_TXT
                    }
                    pst.setInt(12, row); // id (doppelt)
                    pst.executeUpdate();                             
                }
            }
        } 
    }

Du solltest das PreparedStatement erst befüllen, und dann die Query ausführen.

etwa:
Java:
try (PreparedStatement pst = conn.prepareStatement(sql)) {
    pst.setInt(1, row); // id
    pst.setString(2, label); //LABEL
    ....
    pst.executeUpdate()
}
ResultSet ist dabei überflüssig, du willst ja ein Update und kein Select ausführen.
 
M

maGG

Bekanntes Mitglied
haha naja Methoden ausgelagert habe ich noch nicht soviele und es ist viel noch auskommentiert, da wird einiges an Zeilen wieder von verschwinden.
Hat mit deinen Tipps auf jeden Fall geklappt jetzt, hab noch ein paar Datentypen Fehler, aber die krieg ich morgen bestimmt noch weg, Dankeschön! :)
 
mihe7

mihe7

Top Contributor
naja Methoden ausgelagert habe ich noch nicht soviele
Ich hatte im letzten Quartal Fremdcode vor mir, da hatte eine einzige Methode mehr Zeilen - die dafür fast alle sehr ähnlich waren... Da brauchst Du Karte und Kompass, dass Du noch weißt, ob Du an der richtigen Stelle editierst.
 
mrBrown

mrBrown

Super-Moderator
Mitarbeiter
Mehr als 5_000 Zeilen? :O Bei 1/100 der Länge bin ich ja schon kurz davor, laut schreiend im Kreis durchs Büro zu rennen...
 
mihe7

mihe7

Top Contributor
Hab gerade extra nochmal nachgesehen: die Klasse hat 12.380 Zeilen, es gibt ein paar kleinere Methoden sowie eine mit 5.733, eine mit 3.556 und eine mit 1.649 Zeilen...
WTF?!?
 
M

maGG

Bekanntes Mitglied
Hmm bei meiner Vorschau-Methode für die Tabelle wird der erste Wert mit id=1 nicht angezeigt:
Java:
    public void viewTableForeignBranches() throws SQLException{
        String sql = "SELECT * FROM Filialen_Ausland";
        try (PreparedStatement pst = conn.prepareStatement(sql)) {
            try (ResultSet rs = pst.executeQuery()) {
                if (rs.next()) {
                    jTableFilialen_Ausland.setModel(DbUtils.resultSetToTableModel(rs));
                }
            }
        }   
    }
Ne Idee woran das liegen könnte? :)
 
mihe7

mihe7

Top Contributor
Vermutlich lädst Du in Deiner resultSetToTableModel-Methode in einer while-Schleife die Daten. Die Schleifenbedingung wird dort rs.next() sein. D. h. Du rufst zu Beginn rs.next() zweimal auf: einmal hier im if und einmal im while in der Methode.
 
M

maGG

Bekanntes Mitglied
Ich habe noch ein Anliegen: Mein Programm umfasst zwei Fenster. Man kann von einem Fenster zu anderen gelangen. Das habe ich bisher so gelöst:

Java:
//von Fenster 1 zu Fenster 2
this.setVisible(false);
Filialen.setVisible(true); //das zweite Fenster

//von Fenster 2 zu Fenster 1
Filialen.setVisible(false);
this.setVisible(true);

Jetzt wollte ich ja, dass die ComboBox(en) nach Editieren der Datenbank aktualisiert werden. Ein eigenes ComboBox Model zu schreiben kann ich aber nicht und wäre glaub zu aufwändig. Daher kam mir die Idee ich könnte doch von Fenster 2 auf Fenster 1 das Programm einfach neustarten - dann würde die ComboBox(en) richtig befüllt sein.

Kann ich das so machen?

Java:
Filialen.dispose(); //soll das zweite Fenster schließen
GUI.main(null); //soll Programm neustarten

Oder muss ich mit System.exit() arbeiten?

Ich verstehe die Unterschiede nicht so richtig.
 
Zuletzt bearbeitet:
mihe7

mihe7

Top Contributor
Ein eigenes ComboBox Model zu schreiben kann ich aber nicht und wäre glaub zu aufwändig.
Quatsch und Quatsch.

Abgesehen davon: hattest Du nicht eine Methode, die das ComboBox-Model (mit Daten aus der DB) liefert? Dann bräuchtest Du ja nur das Model der ComboBox zu ersetzen.
 
mihe7

mihe7

Top Contributor
Je mehr ich darüber nachdenke, desto weniger verstehe ich, was Du hier eigentlich betreibst. Hast Du mal einen Screenshot oder ähnliches?
 
M

maGG

Bekanntes Mitglied
Abgesehen davon: hattest Du nicht eine Methode, die das ComboBox-Model (mit Daten aus der DB) liefert? Dann bräuchtest Du ja nur das Model der ComboBox zu ersetzen.
Ja, aber dann hatte ich das Problem das die Füllmethode einmal beim Start des Programms ausgeführt wird und dann nochmal beim Klicken des Buttons "Zurück zum Hauptfenster". Das heißt für die ComboBox, dass die sie doppelt befüllt wird. Das könnte ich mit Löschen und dann Befüllen lösen, aber dann fehlt der erste Wert mit "Bitte auswählen".

Hier mal zwei Bilder zum Verständnis:

Erstes Fesnter (Hauptfenster):
11667


Zweites Fenster (zum Editieren der DB):
11668
 

Ähnliche Java Themen

Anzeige

Neue Themen


Oben