Daten aus errechneter Methode in Datenbank(SQLite) schreiben

MasterShredder

Aktives Mitglied
Hallo,
ich versuche von meinem Verbrauchsrechner(Strom, Gas) errechnete Daten in eine SQLite Datenbank zu schreiben.
Doch dies will nicht gelingen. Die Datenbank Einbindung an sich funktioniert. Manuelles reinschreiben über insert() ist kein Problem.
Doch sobald ich Versuche die errechneten Daten reinzuschreiben geht es nicht.

Erst habe ich es mit dem direkten Aufruf über ein Objekt.Variable versucht(wie, auch noch im Quelltext zu sehen), was aber nicht funktionierte.
Dann habe ich es über Getter in der StromPanel Klasse versucht auch nichts. Danach habe ich es noch mit Settern in der Verbrauchsrechner Klasse versucht doch nichts.

Hier noch ein kleines UML Diagramm für eine Übersicht:
uml_diagramm_Verbauchsrechner.png

Die Klasse Verbauchsrechner:
Java:
package hauptprogramm;

import subclasses.Aufzeichnungen;
import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;

import datenbank.DatenbankSchreiben;

/**
 * Verbrauchsrechner: Zur Ermittlung meines Strom und Gas Verbrauches
 * @author MasterShredder
 * @version 2.0
 */
public class Verbrauchsrechner {

    public void run() {
    JFrame frame = new JFrame();
    GasPanel gp = new GasPanel();
    StromPanel sp = new StromPanel();
    Aufzeichnungen aufzeichnung = new Aufzeichnungen(gp, sp);
//Erstellung Menübar
    JMenuBar bar = new JMenuBar();
    JMenu werteMenu = new JMenu("Werte");
    
    JMenu speichernMenu = new JMenu("Werte speichern");
    //GasPanel speichern
    JMenuItem speiGas = new JMenuItem("Gas Panel");   
    speiGas.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            
            aufzeichnung.gasSchreiben();
            
        }
    });
    
    //StromPanel speichern
    JMenuItem speiStrom = new JMenuItem("Strom Panel");
    speiStrom.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            
          
                DatenbankSchreiben stromwerteSchreiben = new DatenbankSchreiben();
                StromPanel getStromPanel = new StromPanel();
                
                // insert new rows
                stromwerteSchreiben.insert(getStromPanel.aktStand, "juhu");               

                //Alle Zeilen ausgeben
                stromwerteSchreiben.selectAll();
        }
    });
    
    speichernMenu.add(speiGas);
    speichernMenu.add(speiStrom);
    werteMenu.add(speichernMenu);
    bar.add(werteMenu);
    
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    frame.add(gp, BorderLayout.CENTER);
    frame.add(sp, BorderLayout.EAST);
    frame.add(bar, BorderLayout.NORTH);
                
    frame.setSize(1000, 450);
    frame.setVisible(true);
    }
        
    
    public static void main(String[] args) {
         SwingUtilities.invokeLater(() -> new Verbrauchsrechner().run());         
    }
}

DatenSchreiben für die Einbindung der Datenbank:
Java:
package datenbank;

import java.sql.Statement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class DatenbankSchreiben {
    
        /**
         * Connect to the verdaten.db database
         *
         * @return the Connection object
         */
        private Connection connect() {
            // SQLite connection string
            String url = "jdbc:sqlite:verdaten.db";
            Connection conn = null;
            try {
                conn = DriverManager.getConnection(url);
            } catch (SQLException e) {
                System.out.println(e.getMessage());
            }
            return conn;
        }

        /**
         * Insert a new row into the Strom table
         *
         * @param a
         * @param b
         */
        public void insert(double a, String b) {
            String sql = "INSERT INTO strom(a,b) VALUES(?,?)";

            try (Connection conn = this.connect();
                    PreparedStatement pstmt = conn.prepareStatement(sql)) {
                pstmt.setDouble(1, a);
                pstmt.setString(2, b);
                pstmt.executeUpdate();
            } catch (SQLException e) {
                System.out.println(e.getMessage());
            }
        }
        
        //selectAll() Method
        public void selectAll(){
            String sql = "SELECT a, b FROM strom";
            
            try (Connection conn = this.connect();
                 Statement stmt  = conn.createStatement();
                 ResultSet rs    = stmt.executeQuery(sql)){
                
                // loop through the result set
                while (rs.next()) {
                    System.out.println(rs.getDouble("a") + "\t" +
                                       rs.getString("b"));
                }
            } catch (SQLException e) {
                System.out.println(e.getMessage());
            }
        }

    }

Ausschnitt StromPanel:
Java:
public class StromPanel extends JPanel {
    
//Attribute
    private static double PREISKWH=23.54, ZAEHLERSTANDKELLER=114893, GRUNDGEBUEHR=81.81, VORJHBETRAG=398.23, VORJHBETRAGOGRUND=257.29;
    public double aktStand, zaehlerstandEingabe, aktKosten, differenzVJ, kostenOGrundg, diffVJoGrundg;
    //Einheiten
    public String kwhEin="kWh",euroEin="\u20AC";
    
    
    
    /**
 * Verrechnen: Aktueller Stand wird ermittelt
 * Aktuelle Kosten ermitteln(Stand/kWh * Preis/kWh / 100(in Euro umwandeln) + Grundgebühr + 19% UST.
 * Die Differenz zum Vorjahr wird ermittelt
 * Ausgabe einmal mit und ohne Grundgebuehr
 */
    private void verrechnen() {                       
        
        aktStand = zaehlerstandEingabe - ZAEHLERSTANDKELLER;             
        
        kostenOGrundg = Math.round(aktStand * PREISKWH / 100);       
        aktKosten = Math.round(kostenOGrundg + GRUNDGEBUEHR * 1.19);       
        
        differenzVJ = Math.round(aktKosten - VORJHBETRAG);
        diffVJoGrundg = Math.round(kostenOGrundg - VORJHBETRAGOGRUND);
        }
    
    
    
    //Button Aufruf verrechnen()
        JButton btnOk = new JButton("OK");
        gbc.anchor = GridBagConstraints.CENTER;
        gbl(1, 6, 1, 1);
        gbc.ipadx = 30;
        gbc.ipady = 3;
        btnOk.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                zaehlerstandEingabe = Double.parseDouble(tFzaehlerstandEingabe.getText());
                verrechnen();
                anzAktKosten.setText(aktKosten + "");
                anzDifferenzVJ.setText(differenzVJ + "");
                anzAktStand.setText(aktStand + "");
                anzKostenOgrundG.setText(kostenOGrundg + "");
                anzDiffVjOgrundg.setText(diffVJoGrundg + "");
            }
        });       
        // Mit Enter auslössen
        tFzaehlerstandEingabe.addKeyListener(new KeyListener() {
            @Override
            public void keyTyped(KeyEvent e) {               
            }
            @Override
            public void keyReleased(KeyEvent e) {
            }           
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode()==KeyEvent.VK_ENTER) {
                    zaehlerstandEingabe = Double.parseDouble(tFzaehlerstandEingabe.getText());
                    verrechnen();
                    anzAktKosten.setText(aktKosten + "");                   
                    anzDifferenzVJ.setText(differenzVJ + "");
                    anzAktStand.setText(aktStand + "");
                    anzKostenOgrundG.setText(kostenOGrundg + "");
                    anzDiffVjOgrundg.setText(diffVJoGrundg + "");
                }               
            }
        });
        
        add(btnOk, gbc);
    }

Woran könnte dies liegen?

MFG
MasterShredder
 

Oneixee5

Top Contributor
Zunächst ist es eine schlechte Idee berechnete Werte in eine DB zu schreiben. Eine Änderung eines Wertes hat dann zur Folge, das der berechnete Wert falsch ist. Das Problem wird immer größer je mehr berechnete Werte oder berechnete Werte von berechneten Werten gespeichert werden. Das Problem lässt sich einfach mit Views umgehen. Das Prinzip ist einfach, man erstellt im Prinzip eine Abfrage inkl. Berechnung und legt diese als Datenbankobjekt an. Durch Abfrage der View hat man dann immer automatisch die aktuellen Ergebnisse, egal wie viele Daten seit der letzten Anzeige der View geändert wurden.
Eine weiter Möglichkeiten sind Funktionen als Spaltentyp, So ist es z.B. möglich immer den aktuellen Anteil der Mehrwertsteuer ails Spalte verfügbar zu haben, ohne einen konkreten Wert dafür zu speichern.
SQL:
CREATE TABLE products(
    name TEXT NOT NULL,
    price REAL NOT NULL,
    discount REAL NOT NULL,
    tax REAL NOT NULL,
    net_price REAL GENERATED ALWAYS
        AS (price * (1-discount) * (1+tax))
);
 
Y

yfons123

Gast
Java:
In SQL, a view is a virtual table based on the result-set of an SQL statement.

A view contains rows and columns, just like a real table. The fields in a view are fields from one or more real tables in the database.

You can add SQL statements and functions to a view and present the data as if the data were coming from one single table.

bei einer View tust du "wie wenn" die Tabelle da wäre

du kannst zb in einer View schon die Formel zum berechnen in den Select rein schreiben und sobald du von der view selektierst rechnet sich der SQL Server das dann aus

somit kannst du deine Tabellen normalisieren und in die views packst du tabellen rein um gemütlicher zugriff drauf zu haben

das mal als extra zu den erwähnten views


was auch in einem anderen thread war da hat einer versucht den job einer datenbank wie zb massen erzeugung von kombinationen selber zu erledigen und hatte dann einen Mathe Fehler und es haben sich fehler ergeben... also lass die Datenbank das machen was sie gut kann und den Rest machst du in java, versuche nicht die Datenbank in ihrem eigenen Spiel zu besiegen
 
Zuletzt bearbeitet von einem Moderator:

MasterShredder

Aktives Mitglied
Hallo,

erst mal danke für die schnelle Antwort.

Mhh, aber ich glaube ihr habt da etwas falsch verstanden! Also es soll nicht dauerhaft in die Datenbank geschrieben werden.

Ich will nur ab und an mal, die Ergebnisse meines Verbrauchs manuell abspeichern.
So dass ich später sehen kann was ich in welchem Zeitraum verbraucht habe.
 
Y

yfons123

Gast
du hast mal vergessen einen Eintrag hinzuzfügen

dann fügst du den Eintrag nachträglich hinzu udn puff alle ergebnisse falsch
 

MasterShredder

Aktives Mitglied
Mhh, OK. Denke ungefähr habe ich das mit den views verstanden. Also jedenfalls das mit der einfacheren Abfrage. Aber ich möchte schon den konkreten Wert abspeichern.. Aber ich sehe es mir mal an.

Nur wie bekomme ich die berrechneten Werte aus dem StromPanel(es gibt auch noch ein GasPanel) nun in die Klasse wo ixh sie brauche?
 

MasterShredder

Aktives Mitglied
Hello,

nein, eine Fehlermeldung gibt es nicht. Es stehen nur keine Daten beim Abruf bzw. 0.0.
Hast du mal versucht: conn.commit(); explizit aufzurufen?
Nein, wo soll ich sie den aufrufen? Und was soll dies bewirken? Habe hier eine Erklärung aus eclipse(Übersetzt):
Code:
Macht alle Änderungen, die seit dem letzten Commit/Rollback vorgenommen wurden, dauerhaft und gibt alle Datenbanksperren frei, die derzeit von diesem Verbindungsobjekt gehalten werden. Diese Methode sollte nur verwendet werden, wenn der Auto-Commit-Modus deaktiviert wurde.
Löst aus:
SQLException - wenn ein Datenbankzugriffsfehler auftritt, diese Methode während der Teilnahme an einer verteilten Transaktion aufgerufen wird, wenn diese Methode auf einer geschlossenen Verbindung aufgerufen wird oder dieses Connection-Objekt sich im Auto-Commit-Modus befindet
Siehe auch:
setAutoCommit
 

mihe7

Top Contributor
Nein, wo soll ich sie den aufrufen? Und was soll dies bewirken?
Nach dem Insert (d. h. nach Zeile 42)

Was das bewirkt? RDBMS arbeiten mit Transaktionen, ein commit schließt eine Transaktion ab (ein rollback macht eine Transaktion rückgängig).

Du kannst also mehrere SQL-Befehle in einer Transaktion absetzen. Beim Commit gilt das "alles oder nichts"-Prinzip (Atomarität): wenn der Commit erfolgreich war, ist die gesamte Transaktion dauerhaft. War er nicht erfolgreich, findet sich kein Teil der Transaktion in der DB.
 

MasterShredder

Aktives Mitglied
Hallo @mihe7 ,
Was das bewirkt? RDBMS arbeiten mit Transaktionen, ein commit schließt eine Transaktion ab (ein rollback macht eine Transaktion rückgängig).
Ok habe ich verstanden.

Du kannst also mehrere SQL-Befehle in einer Transaktion absetzen.
OK wäre dies bei mir jetzt hier allein "INSERT INTO"?

wenn der Commit erfolgreich war, ist die gesamte Transaktion dauerhaft. War er nicht erfolgreich, findet sich kein Teil der Transaktion in der DB.
Das verstehe ich nicht ganz was heißt "dauerhaft" oder "kein Teil" oder soll dies bedeuten dass die Ganzen Daten(Einträge) geschrien sind oder nicht?

Habe es damit probiert aber "Nichts" Ausgabe unverändert:
Screenshot_20221204_202308.png
Nicht erschrecken Daten sind Entwickler Version😄.


Und Noch ein Vermerk, ich habe etwas umstrukturiert:
uml_diagramm_Verbauchsrechner.png
Die Pfeile sollen nur "meinen" geschätzten oder erwarteten Weg darstellen.
 

MasterShredder

Aktives Mitglied
Nachtrag: Achso und mit dem explizitem Aufruf von commit() haben wir jetzt sichergestellt dass, die Transaktion erfolgreich war?
Also, da ich jetzt noch immer keine Daten aus der Ausgabe bekomme muss es an etwas anderem liegen?
 

mihe7

Top Contributor
Das verstehe ich nicht ganz was heißt "dauerhaft" oder "kein Teil" oder soll dies bedeuten dass die Ganzen Daten(Einträge) geschrien sind oder nicht?
Richtig.

Dauerhaft heißt: die Daten müssen tatsächlich auf dem Speichermedium gespeichert sein. Wenn der Commit durchgeht und Du sofort den Netzstecker ziehst (vielleicht nicht grade beim Notebook :)), dann dürfen die Daten nicht in irgendeinem Cache liegen, sonst wären sie weg.

Zum zweiten Teil: stell Dir mal ein Buchhaltungssystem vor. In der doppelten Buchführung hättest Du z. B. etwas wie: Journal #132, 04.12.2022, Forderungen an Erlöse, 100 €, netto, voller MwSt-Satz. Daraus werden dann z. B. drei Buchungen, die über die Journalnummer miteinander verknüpft sind. Auf Konto "Forderungen" werden 119 € gebucht, auf Erlöse 100 € und auf USt 19 €. Das sind dann drei Inserts. Jetzt darf es natürlich nicht passieren, dass beim letzten Insert ein Fehler auftritt und in der DB die ersten beiden stehen bleiben. Deswegen würde man so etwas in einer Transaktion ablaufen lassen:
Code:
BEGIN TRANSACTION (das läuft implizit)
INSERT INTO Forderung VALUES (132, '2022-12-04', 119, 'Rechnung vom 04.12.2022', 'AR482817/2022');
INSERT INTO Erloese VALUES (132, '2022-12-04', 100, 'Rechnung vom 04.12.2022', 'AR482817/2022');
INSERT INTO USt VALUES (132, '2022-12-04', 19, 'Rechnung vom 04.12.2022', 'AR482817/2022');
COMMIT TRANSACTION
Erst, wenn der COMMIT erfolgreich durchläuft, kannst Du sicher sein, dass die INSERTS tatsächlich in der DB stehen. Normalerweise ist der Isolationsgrad so eingestellt, dass andere Benutzer (bzw. Sessions) die INSERTS auch erst nach dem COMMIT sehen. Würde beim letzten INSERT ein Fehler festgestellt, würde die DB alle vorangegangenen INSERTs dieser Transaktion zurücknehmen. Einen ROLLBACK kann man auch manuell auslösen.

Es gibt normalerweise auch einen autocommit-Modus. Bei dem wird nach jedem Statement automatisch ein Commit durchgeführt. Wenn man manuell an der DB hantiert, empfiehlt es sich, autocommit abzuschalten. Hat man einen Fehler gemacht, kann man seine Änderungen mit eine ROLLBACK ruckzuck wieder korrigieren.

Ein RDBMS garantiert normalerweise die ACID-Eigenschaften, das kannst Du unter https://de.wikipedia.org/wiki/ACID aber vermutlich besser nachlesen. Technisch werden z. B. Sperrmechanismen eingesetzt. Bei einem Commit werden solche Sperren dann auch wieder freigegeben.

Achso und mit dem explizitem Aufruf von commit() haben wir jetzt sichergestellt dass, die Transaktion erfolgreich war?
Ja, wobei die Frage wäre, ob Du den überhaupt gebraucht hättest oder der Autocommit-Mode aktiv war.

Also, da ich jetzt noch immer keine Daten aus der Ausgabe bekomme muss es an etwas anderem liegen?
Hast Du schon mal direkt in die DB geschaut (oder ohne Java)?
 

DefconDev

Bekanntes Mitglied
Anstatt eines Inserts , zumindest laut Methodenname im Code wird aber ein Update durchgeführt. Ist das gewollt?

pstmt.executeUpdate()
 

mihe7

Top Contributor
@DefconDev das ist schon ok, executeUpdate() ist insbesondere für DML und Anfragen gedacht, die nichts zurückliefern.

Aber dort steht auch nichts drin. Gleicher Inhalt wie Konsole nur(mehr) nicht nur die letzten 4 Zeilen.
D. h. es steht etwas drin, nur nicht das, was Du willst.

Ich habe mir jetzt mal Deinen Code etwas genauer angesehen. Das Problem ist doch, dass Du speicherst, sobald Du das Panel erzeugst, da ist aktStand natürlich 0 und das wird offensichtlich auch in die DB eingetragen.

Bau mal einen expliziten Speicher-Button ein, der sich die aktuellen Werte aus dem Panel holt und an die insert-Methode übergibt, dann sollte das auch funktionieren.

Nebenbei: in StromPanel sind die Zeilen 38 bis 44 und 58 bis 64 identisch -> solltest Du in eine Methode auslagern.
 

MasterShredder

Aktives Mitglied
D. h. es steht etwas drin, nur nicht das, was Du willst.
Ja oder so😄.
Das Problem ist doch, dass Du speicherst, sobald Du das Panel erzeugst, da ist aktStand natürlich 0
OK. Das verstehe ich jetzt nicht ganz ???.
Bau mal einen expliziten Speicher-Button ein
Habe ich getan und das mit Erfolg👍. Hat den aktStand eingetragen.

Nebenbei: in StromPanel sind die Zeilen 38 bis 44 und 58 bis 64 identisch -> solltest Du in eine Methode auslagern.
Ok danke, sehe ich mir mal an.
 

mihe7

Top Contributor
OK. Das verstehe ich jetzt nicht ganz ???.
In den Zeilen 43 bis 50 der Klasse Verbrauchsrechner aus Deinem Ursprungspost steht:
Java:
                DatenbankSchreiben stromwerteSchreiben = new DatenbankSchreiben();
                StromPanel getStromPanel = new StromPanel();
               
                // insert new rows
                stromwerteSchreiben.insert(getStromPanel.aktStand, "juhu");              

                //Alle Zeilen ausgeben
                stromwerteSchreiben.selectAll();
Hier erzeugst Du a) ein neues StromPanel, holst Dir b) den aktStand (der zu diesem Zeitpunkt natürlich noch 0 ist) und schreibst ihn c) zusammen mit "juhu" in die DB. Anschließend lässt Du Dir die Werte der DB ausgeben.
 

MasterShredder

Aktives Mitglied
Hier erzeugst Du a) ein neues StromPanel,
Ah ja, klar, es ist ja ein neues Objekt und nicht das eigentliche welches die Daten schon verarbeitet hat:).
Also habe ich mal das Hauptobjekt(die Hauptinstanz?) genommen. Uns siehe da
Screenshot_20221207_003255.png
Es funktioniert. Jetzt ist nur halt die Frage ob dies so in Ordnung ist und auch sinnvoll .
Java:
package hauptprogramm;

import subclasses.Aufzeichnungen;
import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;

import datenbank.DatenbankSchreiben;

/**
 * Verbrauchsrechner: Zur Ermittlung meines Strom und Gas Verbrauches
 * @author MasterShredder
 * @version 2.0
 */
public class Verbrauchsrechner {
    
     DatenbankSchreiben stromwerteSchreiben = new DatenbankSchreiben();

    public void run() {
    JFrame frame = new JFrame();
    GasPanel gp = new GasPanel();
    StromPanel sp = new StromPanel();
    Aufzeichnungen aufzeichnung = new Aufzeichnungen(gp, sp);
//Erstellung Menübar
    JMenuBar bar = new JMenuBar();
    JMenu werteMenu = new JMenu("Werte");
    
    JMenu speichernMenu = new JMenu("Werte speichern");
    //GasPanel speichern
    JMenuItem speiGas = new JMenuItem("Gas Panel");   
    speiGas.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            
            aufzeichnung.gasSchreiben();
            
        }
    });
    
    //StromPanel speichern
    JMenuItem speiStrom = new JMenuItem("Strom Panel");
    speiStrom.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {               
                
                // insert new rows
                stromwerteSchreiben.insert(sp.aktStand, "VersucheObjekt");               

                //Alle Zeilen ausgeben
                stromwerteSchreiben.selectAll();
        }
    });
    
    speichernMenu.add(speiGas);
    speichernMenu.add(speiStrom);
    werteMenu.add(speichernMenu);
    bar.add(werteMenu);
    
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    frame.add(gp, BorderLayout.CENTER);
    frame.add(sp, BorderLayout.EAST);
    frame.add(bar, BorderLayout.NORTH);
                
    frame.setSize(1000, 450);
    frame.setVisible(true);
    }
        
    
    public static void main(String[] args) {
         SwingUtilities.invokeLater(() -> new Verbrauchsrechner().run());         
    }
}

Nebenbei: in StromPanel sind die Zeilen 38 bis 44 und 58 bis 64 identisch -> solltest Du in eine Methode auslagern.
Habe ich versucht, doch egal wo ich die Methode dann hinschreibe(Am Anfang, Ende der Klasse, im Button Aufruf) es gibt immer Fehler:
Code:
Diese Zeile enthält Mehrfachmarkierungen
    - void ist ein ungültiger Typ für die Variable ausgebenTf
    - Syntaxfehler bei Token "void", record erwartet
Java:
//Action und Eingabe
        JLabel lblZaehlerstandEingabe = new JLabel("Zählerstand:");
        gbc.anchor = GridBagConstraints.LINE_START;
        gbl(0, 5, 1, 1);
        add(lblZaehlerstandEingabe, gbc);
        
        JTextField tFzaehlerstandEingabe = new JTextField();
        tFzaehlerstandEingabe.setBackground(UIManager.getColor("Button.background"));
        tFzaehlerstandEingabe.setPreferredSize(new Dimension(80, 20));
        AbstractDocument doc = (AbstractDocument) tFzaehlerstandEingabe.getDocument();
        doc.setDocumentFilter(new IntegerFilter());
        gbc.anchor = GridBagConstraints.CENTER;
        gbl(1, 5, 1, 1);
        add(tFzaehlerstandEingabe, gbc);
        
        JLabel lblZaehlerstandEingabeEin = new JLabel(kwhEin);
        gbc.anchor = GridBagConstraints.LINE_START;
        gbl(2, 5, 1, 1);
        add(lblZaehlerstandEingabeEin, gbc);
        
                
//Button Aufruf verrechnen()
        JButton btnOk = new JButton("OK");
        gbc.anchor = GridBagConstraints.CENTER;
        gbl(1, 6, 1, 1);
        gbc.ipadx = 30;
        gbc.ipady = 3;
        public void ausgebenTf() {
            zaehlerstandEingabe = Double.parseDouble(tFzaehlerstandEingabe.getText());
            verrechnen();
            anzAktKosten.setText(aktKosten + "");                   
            anzDifferenzVJ.setText(differenzVJ + "");
            anzAktStand.setText(aktStand + "");
            anzKostenOgrundG.setText(kostenOGrundg + "");
            anzDiffVjOgrundg.setText(diffVJoGrundg + "");
        }
        btnOk.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                zaehlerstandEingabe = Double.parseDouble(tFzaehlerstandEingabe.getText());
                verrechnen();
                anzAktKosten.setText(aktKosten + "");
                anzDifferenzVJ.setText(differenzVJ + "");
                anzAktStand.setText(aktStand + "");
                anzKostenOgrundG.setText(kostenOGrundg + "");
                anzDiffVjOgrundg.setText(diffVJoGrundg + "");
            }
        });
        
        
        // Mit Enter auslössen
        tFzaehlerstandEingabe.addKeyListener(new KeyListener() {
            @Override
            public void keyTyped(KeyEvent e) {               
            }
            @Override
            public void keyReleased(KeyEvent e) {
            }           
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode()==KeyEvent.VK_ENTER) {
                    zaehlerstandEingabe = Double.parseDouble(tFzaehlerstandEingabe.getText());
                    verrechnen();
                    anzAktKosten.setText(aktKosten + "");                   
                    anzDifferenzVJ.setText(differenzVJ + "");
                    anzAktStand.setText(aktStand + "");
                    anzKostenOgrundG.setText(kostenOGrundg + "");
                    anzDiffVjOgrundg.setText(diffVJoGrundg + "");
                }               
            }
        });
                        
        add(btnOk, gbc);
 

mihe7

Top Contributor
Es funktioniert. Jetzt ist nur halt die Frage ob dies so in Ordnung ist und auch sinnvoll .
Gefährliche Frage :p

Sagen wir mal so: ob das für Dich in Ordnung ist, musst Du wissen. Mir gefallen ein paar Dinge nicht besonders, z. B. der Klassenname "DatenbankSchreiben". Eine Klasse ist keine Tätigkeit, außerdem schreibt die Klasse nicht nur, sondern liest ja auch Daten aus der DB. Was mir gar nicht gefällt, dass es keine Trennung zwischen Daten und UI gibt. Die fehlende Kapselung in StromPanel ist auch nicht gerade schön. Das mal ganz grob.

Habe ich versucht, doch egal wo ich die Methode dann hinschreibe(Am Anfang, Ende der Klasse, im Button Aufruf) es gibt immer Fehler:
Da müsstest Du mal die komplette Klasse posten.
 

MasterShredder

Aktives Mitglied
Mir gefallen ein paar Dinge nicht besonders, z. B. der Klassenname "DatenbankSchreiben". E
Ja das war auch nur ein vorläufiger Test Projektname.
Was mir gar nicht gefällt, dass es keine Trennung zwischen Daten und UI gibt.
Ah ok ich nehme mal an du meinst weil ich jetzt auf das Objekt "sp" was eigentlich für den GUI Aufbau(separater Thread) da ist zugreife um die Daten zu verarbeiten.

Also bräuchten wir dafür einen extra Thread?
Java:
package hauptprogramm;

import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;
import datenbank.Datenbank;

/**
 * Verbrauchsrechner: Zur Ermittlung meines Strom und Gas Verbrauches
 * @author MasterShredder
 * @version 2.0
 */
public class Verbrauchsrechner {
    //dbConnection
     Datenbank dbCon = new Datenbank();

    public void run() {
    JFrame frame = new JFrame();
    GasPanel gp = new GasPanel();
    StromPanel sp = new StromPanel();   
//Erstellung Menübar
    JMenuBar bar = new JMenuBar();
    JMenu werteMenu = new JMenu("Werte");
    
    JMenu speichernMenu = new JMenu("Werte speichern");
    //GasPanel speichern
    JMenuItem speiGas = new JMenuItem("Gas Panel");   
    speiGas.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            
                        
        }
    });
    
    //StromPanel speichern
    JMenuItem speiStrom = new JMenuItem("Strom Panel");
    speiStrom.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {               
                dbCon.insert(sp.aktStand, "NeueDatenbankFunktion");
                dbCon.selectAll();
        }
    });
    
    speichernMenu.add(speiGas);
    speichernMenu.add(speiStrom);
    werteMenu.add(speichernMenu);
    bar.add(werteMenu);
    
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    frame.add(gp, BorderLayout.CENTER);
    frame.add(sp, BorderLayout.EAST);
    frame.add(bar, BorderLayout.NORTH);
                
    frame.setSize(1000, 450);
    frame.setVisible(true);
    }
        
    
    public static void main(String[] args) {
         SwingUtilities.invokeLater(() -> new Verbrauchsrechner().run());         
    }
}

Die fehlende Kapselung in StromPanel ist auch nicht gerade schön.
Ja also um mal noch auf den Anfang zurück zu kommen was @yfons123 und @Oneixee5 denke ich ansprachen.
lass die Datenbank das machen was sie gut kann
Ich habe mir überlegt alle meine Daten also (hier Konstanten) in die Datenbank zu schreiben. Und bei einer Verarbeitung dann auch von dort abzuarbeiten. So bin ich auch viel flexibler was das ändern der Daten betrifft(da die eh momentan eine Katastrophe sind MwSt etc...) und ich habe alles beisammen, Werte und die bei der Verrechnung verwendeten Daten.

Da müsstest Du mal die komplette Klasse posten.
Java:
package hauptprogramm;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.AbstractDocument;

import subclasses.IntegerFilter;

/**
 * Strom Panel zur Berechnung meines Stromverbrauches
 * @author MasterShredder
 */
public class StromPanel extends JPanel {
    
//Attribute
    private static double PREISKWH=23.54, ZAEHLERSTANDKELLER=114893, GRUNDGEBUEHR=81.81, VORJHBETRAG=398.23, VORJHBETRAGOGRUND=257.29;
    public double aktStand, zaehlerstandEingabe, aktKosten, differenzVJ, kostenOGrundg, diffVJoGrundg;
    //Einheiten
    public String kwhEin="kWh",euroEin="\u20AC";
    
    //GridBagContrains Objekt
    GridBagConstraints gbc = new GridBagConstraints();


/**
 * Konstruktor: Zuweisung GridBagLayout
 * Setzen der bevorzugten Groeße
 * Erstellen und Zuweisung des insets Objektes
 */
    public StromPanel() {           
        setLayout(new GridBagLayout());               
        setPreferredSize(new Dimension(500, 400));
        gbc.insets = new Insets(2, 2, 2, 2);
        fenster();
        }   
    
/**
 * Verrechnen: Aktueller Stand wird ermittelt
 * Aktuelle Kosten ermitteln(Stand/kWh * Preis/kWh / 100(in Euro umwandeln) + Grundgebühr + 19% UST.
 * Die Differenz zum Vorjahr wird ermittelt
 * Ausgabe einmal mit und ohne Grundgebuehr
 */
    private void verrechnen() {                       
        
        aktStand = zaehlerstandEingabe - ZAEHLERSTANDKELLER;             
        
        kostenOGrundg = Math.round(aktStand * PREISKWH / 100);       
        aktKosten = Math.round(kostenOGrundg + GRUNDGEBUEHR * 1.19);       
        
        differenzVJ = Math.round(aktKosten - VORJHBETRAG);
        diffVJoGrundg = Math.round(kostenOGrundg - VORJHBETRAGOGRUND);
        }
        
/**
 * Hilfsmethode Zuweisungen fuer GridBagLayout
 * @param gx Position x Achse
 * @param gy Position y Achse
 * @param gw width geben die Anzahl der von der Komponente verwendeten Zellen an
 * @param gh height geben die Anzahl der von der Komponente verwendeten Zellen an
 */
    public void gbl(int gx, int gy, int gw, int gh) {
        gbc.gridx = gx;
        gbc.gridy = gy;
        gbc.gridwidth = gw;
        gbc.gridheight = gh;
    }
    
        
/**
 * Fensteraufbau: Beinhaltet die GUI Elemente
 * Und Listener zum ausfuehren der Berechnung   
 */
    public void fenster() {
        
//Versorger Info
        StromVersorgerinfo verInfo = new StromVersorgerinfo();
        gbl(0, 0, 5, 1);
        gbc.anchor = GridBagConstraints.CENTER;
        add(verInfo, gbc);
        
        
//Beschriftung Aktuell und Vorjahr
        JLabel lblAktuell = new JLabel("Aktuell");
        gbc.anchor = GridBagConstraints.CENTER;
        gbl(1, 1, 1, 1);
        add(lblAktuell, gbc);

        JLabel lblVorjahr = new JLabel("Vorjahr");
        gbc.anchor = GridBagConstraints.CENTER;
        gbl(3, 1, 1, 1);
        add(lblVorjahr, gbc);

//Aktueller Stand
        JLabel lblAktuellerStand = new JLabel("Aktueller Stand:");
        gbc.anchor = GridBagConstraints.LINE_START;
        gbl(0, 2, 1, 1);
        add(lblAktuellerStand, gbc);
        
        JLabel anzAktStand = new JLabel();
        anzAktStand.setPreferredSize(new Dimension(70, 20));
        anzAktStand.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        gbc.anchor = GridBagConstraints.CENTER;
        gbl(1, 2, 1, 1);
        add(anzAktStand, gbc);
        
        JLabel lblAktuellerStandEin = new JLabel(kwhEin);
        gbc.anchor = GridBagConstraints.LINE_START;
        gbl(2, 2, 1, 1);
        add(lblAktuellerStandEin, gbc);

        
//Betrag ohne Grundgebuehr
        JLabel lblKostenOGrundgebuehr = new JLabel("Betrag ohne Grundgebühr:");
        gbc.anchor = GridBagConstraints.LINE_START;
        gbl(0, 3, 1, 1);
        add(lblKostenOGrundgebuehr, gbc);
                
        JLabel anzKostenOgrundG = new JLabel();
        anzKostenOgrundG.setPreferredSize(new Dimension(70, 20));
        anzKostenOgrundG.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        gbc.anchor = GridBagConstraints.CENTER;
        gbl(1, 3, 1, 1);
        add(anzKostenOgrundG, gbc);
                
        JLabel lblKostenOgrundgEin = new JLabel(euroEin + "");
        gbc.anchor = GridBagConstraints.LINE_START;
        gbl(2, 3, 1, 1);
        add(lblKostenOgrundgEin, gbc);

//Differenz Vorjahr ohne Grundgebuehr
        JLabel anzDiffVjOgrundg = new JLabel();
        anzDiffVjOgrundg.setPreferredSize(new Dimension(70, 20));
        anzDiffVjOgrundg.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        gbc.anchor = GridBagConstraints.CENTER;
        gbl(3, 3, 1, 1);
        add(anzDiffVjOgrundg, gbc);
                
        JLabel lblDiffVjOgrundgEin = new JLabel(euroEin + "");
        gbc.anchor = GridBagConstraints.LINE_START;
        gbl(4, 3, 1, 1);
        add(lblDiffVjOgrundgEin, gbc);
                
//Aktueller Rechnungsbetrag
        JLabel lblAktKosten = new JLabel("Akt. Kosten(Brutto):");
        gbc.anchor = GridBagConstraints.LINE_START;
        gbl(0, 4, 1, 1);
        add(lblAktKosten, gbc);
        
        JLabel anzAktKosten = new JLabel();
        anzAktKosten.setPreferredSize(new Dimension(70, 20));
        anzAktKosten.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        gbc.anchor = GridBagConstraints.CENTER;
        gbl(1, 4, 1, 1);
        add(anzAktKosten, gbc);
        
        JLabel lblAktKostenEin = new JLabel(euroEin + "");
        gbc.anchor = GridBagConstraints.LINE_START;
        gbl(2, 4, 1, 1);
        add(lblAktKostenEin, gbc);
        
//Differenz Vorjahr
        JLabel anzDifferenzVJ = new JLabel();
        anzDifferenzVJ.setPreferredSize(new Dimension(70, 20));
        anzDifferenzVJ.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        gbc.anchor = GridBagConstraints.CENTER;
        gbl(3, 4, 1, 1);
        add(anzDifferenzVJ, gbc);
        
        JLabel differenzVjEin = new JLabel(euroEin + "");
        gbc.anchor = GridBagConstraints.LINE_START;
        gbl(4, 4, 1, 1);
        add(differenzVjEin, gbc);
        
//Action und Eingabe
        JLabel lblZaehlerstandEingabe = new JLabel("Zählerstand:");
        gbc.anchor = GridBagConstraints.LINE_START;
        gbl(0, 5, 1, 1);
        add(lblZaehlerstandEingabe, gbc);
        
        JTextField tFzaehlerstandEingabe = new JTextField();
        tFzaehlerstandEingabe.setBackground(UIManager.getColor("Button.background"));
        tFzaehlerstandEingabe.setPreferredSize(new Dimension(80, 20));
        AbstractDocument doc = (AbstractDocument) tFzaehlerstandEingabe.getDocument();
        doc.setDocumentFilter(new IntegerFilter());
        gbc.anchor = GridBagConstraints.CENTER;
        gbl(1, 5, 1, 1);
        add(tFzaehlerstandEingabe, gbc);
        
        JLabel lblZaehlerstandEingabeEin = new JLabel(kwhEin);
        gbc.anchor = GridBagConstraints.LINE_START;
        gbl(2, 5, 1, 1);
        add(lblZaehlerstandEingabeEin, gbc);
        
                
//Button Aufruf verrechnen()
        JButton btnOk = new JButton("OK");
        gbc.anchor = GridBagConstraints.CENTER;
        gbl(1, 6, 1, 1);
        gbc.ipadx = 30;
        gbc.ipady = 3;
//        public void ausgebenTf() {
//            zaehlerstandEingabe = Double.parseDouble(tFzaehlerstandEingabe.getText());
//            verrechnen();
//            anzAktKosten.setText(aktKosten + "");                   
//            anzDifferenzVJ.setText(differenzVJ + "");
//            anzAktStand.setText(aktStand + "");
//            anzKostenOgrundG.setText(kostenOGrundg + "");
//            anzDiffVjOgrundg.setText(diffVJoGrundg + "");
//        }
        btnOk.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                zaehlerstandEingabe = Double.parseDouble(tFzaehlerstandEingabe.getText());
                verrechnen();
                anzAktKosten.setText(aktKosten + "");
                anzDifferenzVJ.setText(differenzVJ + "");
                anzAktStand.setText(aktStand + "");
                anzKostenOgrundG.setText(kostenOGrundg + "");
                anzDiffVjOgrundg.setText(diffVJoGrundg + "");
            }
        });
        
        
        // Mit Enter auslössen
        tFzaehlerstandEingabe.addKeyListener(new KeyListener() {
            @Override
            public void keyTyped(KeyEvent e) {               
            }
            @Override
            public void keyReleased(KeyEvent e) {
            }           
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode()==KeyEvent.VK_ENTER) {
                    zaehlerstandEingabe = Double.parseDouble(tFzaehlerstandEingabe.getText());
                    verrechnen();
                    anzAktKosten.setText(aktKosten + "");                   
                    anzDifferenzVJ.setText(differenzVJ + "");
                    anzAktStand.setText(aktStand + "");
                    anzKostenOgrundG.setText(kostenOGrundg + "");
                    anzDiffVjOgrundg.setText(diffVJoGrundg + "");
                }               
            }
        });
                        
        add(btnOk, gbc);   
    }
    
}
 
Y

yfons123

Gast
warum verwurschtelst du die gui elemente mit in den code

du hast doch ganz klare bereiche ( wie jede anwendung )

1. die klicki bunti sektiion mit buttons usw
2. das zeug das dir die sachen ausrechnet ( datenbank, formeln )
3. irgendwas was das verbindet

du hast aktuell alles in eine klasse rein gepflastert... ist ein bisschen wuchtig

außerdem sind deine kommentare ein klassiker, diese sind dafür da um den code in sektionen zu unterteilen, wenn du das willst dann unterteil sie in echte unter sektionen also methoden

du kannst einfach dein kommentar nehmen und diese in methoden namen umwandeln
Java:
public void RechneDifferenzVorjahr(){
   
}
als beispiel

dann merkst du "warum hab ich nen button in einr formel die mir die differenz ausrechnet und dann bist du wieder beim ersten problem

außerdem kann die datenbank auch rechnen in selects, müsstest du nicht mal im code selber machen
 

mihe7

Top Contributor
Also bräuchten wir dafür einen extra Thread?
Auf keinen Fall.

Es geht darum, dass sich Deine GUI-Klassen nicht nur um das GUI kümmern, sondern Logik und Daten enthalten. Damit kennen sich die GUI-Klassen untereinander, ziehen die Daten da raus, um sie abzuspeichern, später dann ggf. wieder zu laden usw. Auf diese Weise erhältst Du eine Anwendung, die schön fragil ist. Das UI dient lediglich als Schnittstelle zwischen dem Anwender und dem Kern Deiner Anwendung. Das UI soll möglichst dumm sein und hat im Wesentlichen nur die Aufgabe, den Zustand der Anwendung (Daten) darzustellen, Eingaben entgegenzunehmen und an den Kern der Anwendung weiterzuleiten. Für ausgefeiltere Ansätze kannst Du mal nach MVC, MVVM und Konsorten googeln, wichtig wäre aber vor allem die Trennung UI und Logik/Daten (View und Model).
 

MasterShredder

Aktives Mitglied
Erstmal danke für die Unterstützung👍 geht mal vorwärts. Dies ist ein Projekt das ich ab und an mal weiter entwickel. Und gerade jetzt in solch einer Zeit wo die Energie Preise schwanken ist dies wirklich eine Hilfe.

@yfons123 Ja da haben wir uns wohl gerade beim posten überschnitten.
warum verwurschtelst du die gui elemente mit in den code
Ja ist mir aufgefallen.
außerdem sind deine kommentare ein klassiker, diese sind dafür da um den code in sektionen zu unterteilen
Ja die habe ich auch ein wenig für die Doc so geschrieben. Um ein wenig Erklärung, Orientierung... zu haben.

wichtig wäre aber vor allem die Trennung UI und Logik/Daten (View und Model).
Ja ich habe mir überlegt und denke das dies vielleicht eine gute Lösung wäre:
ui-logik_umstrukturierung.png
Also die Panel(Strom, Gas) rein nur die GUI Elemente, und in Datenbank die Datenbank Funktionen. Und da die Werte eh in die Datenbank kommen und ich die Datenbank intrigieren kann dort auch die Verrechnung.

In Verbrauchsrechner die run() main(). Und ich denke das Menü müsste dort auch noch raus dann wäre ja die GUI von der Logik komplett getrennt, oder? Und die Buttons der Panel noch natürlich.
 

MasterShredder

Aktives Mitglied
So, ich habe mal etwas umstrukturiert.
Java:
package hauptprogramm;

import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;
import datenbank.Datenbank;

/**
 * Verbrauchsrechner: Zur Ermittlung meines Strom und Gas Verbrauches
 * @author MasterShredder
 * @version 2.0
 */
public class Verbrauchsrechner {
    //dbConnection
     Datenbank dbCon = new Datenbank();

    public void run() {
    JFrame frame = new JFrame();
    GasPanel gp = new GasPanel();
    StromPanel sp = new StromPanel();  
//Erstellung Menübar
    JMenuBar bar = new JMenuBar();
    JMenu werteMenu = new JMenu("Werte");
   
    JMenu speichernMenu = new JMenu("Werte speichern");
    //GasPanel speichern
    JMenuItem speiGas = new JMenuItem("Gas Panel");  
    speiGas.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
           
                       
        }
    });
   
    //StromPanel speichern
    JMenuItem speiStrom = new JMenuItem("Strom Panel");
    speiStrom.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            dbCon.insert(100.50);

               
        }
    });
   
    speichernMenu.add(speiGas);
    speichernMenu.add(speiStrom);
    werteMenu.add(speichernMenu);
    bar.add(werteMenu);
   
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    frame.add(gp, BorderLayout.CENTER);
    frame.add(sp, BorderLayout.EAST);
    frame.add(bar, BorderLayout.NORTH);
               
    frame.setSize(1000, 450);
    frame.setVisible(true);
    }
       
   
    public static void main(String[] args) {
         SwingUtilities.invokeLater(() -> new Verbrauchsrechner().run());        
    }
}
Java:
package datenbank;

import java.sql.Statement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class Datenbank {
   
    public double stromEingabe;
   
    private double kWh, Akt_Kosten, ZstndEndeZeitr;  
           
        public void setStromEingabe(double stromEingabe) {
        this.stromEingabe = stromEingabe;
    }

        /**
         * Connect to the verdaten.db database
         *
         * @return the Connection object
         */
        private Connection connect() {
            // SQLite connection string
            String url = "jdbc:sqlite:datenbank/Verbrauchsdaten.db";
            Connection conn = null;
            try {
                conn = DriverManager.getConnection(url);
            } catch (SQLException e) {
                System.out.println(e.getMessage());
            }
            return conn;
        }

       
        //Insert schreibe DAten in Tabelle        
        public void insert(double Akt_Kosten) {
            String sql = "BEGIN TRANSACTION INSERT INTO verbrauchKosten(Akt_Kosten) VALUES(?) COMMIT";

            try (Connection conn = this.connect();
                    PreparedStatement pstmt = conn.prepareStatement(sql)) {
                conn.setAutoCommit(false);              
                pstmt.setDouble(1, Akt_Kosten);              
               
                pstmt.executeUpdate();
//                conn.commit();
            } catch (SQLException e) {
                System.out.println(e.getMessage());
            }
        }
       
        //selectAll() Method
        public void selectPreis(){
            String sql = "SELECT Kwh_netto FROM vertragsDaten";          
                    //+ "SELECT ZstndEndeZeitr FROM verbrauchKosten";
           
            try (Connection conn = this.connect();
                 Statement stmt  = conn.createStatement();
                 ResultSet rs    = stmt.executeQuery(sql))
            {
               
                // loop through the result set
                while (rs.next()) {
                    System.out.println(rs.getDouble("Kwh_netto")                  
                                                    // + "ZstndEndeZeitr"
                                      );
                   
                    kWh=rs.getDouble("Kwh_netto");
//                    ZstndEndeZeitr=rs.getDouble("ZstndEndeZeitr");
                }
               
               
            } catch (SQLException e) {
                System.out.println(e.getMessage());
            }
        }
       
        public void verrechnen() {
            selectPreis();
            Akt_Kosten = stromEingabe * kWh;
                                    // - ZstndEndeZeitr
            System.out.println("In verrechnen() " + stromEingabe);
            System.out.println("Aktuelle Kosten " + Akt_Kosten);
           
        }

    }
Java:
package hauptprogramm;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.AbstractDocument;

import datenbank.Datenbank;
import subclasses.IntegerFilter;

/**
 * Strom Panel zur Berechnung meines Stromverbrauches
 * @author MasterShredder
 */
public class StromPanel extends JPanel {
   
//Attribute
    //Eingabe
    public    double zaehlerstandEingabe;
    //Einheiten
    public String kwhEin="kWh",euroEin="\u20AC";
   
    //GridBagContrains Objekt
    GridBagConstraints gbc = new GridBagConstraints();


/**
 * Konstruktor: Zuweisung GridBagLayout
 * Setzen der bevorzugten Groeße
 * Erstellen und Zuweisung des insets Objektes
 */
    public StromPanel() {          
        setLayout(new GridBagLayout());              
        setPreferredSize(new Dimension(500, 400));
        gbc.insets = new Insets(2, 2, 2, 2);
        fenster();
        }  
   

/**
 * Hilfsmethode Zuweisungen fuer GridBagLayout
 * @param gx Position x Achse
 * @param gy Position y Achse
 * @param gw width geben die Anzahl der von der Komponente verwendeten Zellen an
 * @param gh height geben die Anzahl der von der Komponente verwendeten Zellen an
 */
    public void gbl(int gx, int gy, int gw, int gh) {
        gbc.gridx = gx;
        gbc.gridy = gy;
        gbc.gridwidth = gw;
        gbc.gridheight = gh;
    }
   
       
/**
 * Fensteraufbau: Beinhaltet die GUI Elemente
 * Und Listener zum ausfuehren der Berechnung  
 */
    public void fenster() {
       
////Versorger Info
//        StromVersorgerinfo verInfo = new StromVersorgerinfo();
//        gbl(0, 0, 5, 1);
//        gbc.anchor = GridBagConstraints.CENTER;
//        add(verInfo, gbc);
       
       
//Beschriftung Aktuell und Vorjahr
        JLabel lblAktuell = new JLabel("Aktuell");
        gbc.anchor = GridBagConstraints.CENTER;
        gbl(1, 1, 1, 1);
        add(lblAktuell, gbc);

        JLabel lblVorjahr = new JLabel("Vorjahr");
        gbc.anchor = GridBagConstraints.CENTER;
        gbl(3, 1, 1, 1);
        add(lblVorjahr, gbc);

//Aktueller Stand
        JLabel lblAktuellerStand = new JLabel("Aktueller Stand:");
        gbc.anchor = GridBagConstraints.LINE_START;
        gbl(0, 2, 1, 1);
        add(lblAktuellerStand, gbc);
       
        JLabel anzAktStand = new JLabel();
        anzAktStand.setPreferredSize(new Dimension(70, 20));
        anzAktStand.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        gbc.anchor = GridBagConstraints.CENTER;
        gbl(1, 2, 1, 1);
        add(anzAktStand, gbc);
       
        JLabel lblAktuellerStandEin = new JLabel(kwhEin);
        gbc.anchor = GridBagConstraints.LINE_START;
        gbl(2, 2, 1, 1);
        add(lblAktuellerStandEin, gbc);

       
//Betrag ohne Grundgebuehr
        JLabel lblKostenOGrundgebuehr = new JLabel("Betrag ohne Grundgebühr:");
        gbc.anchor = GridBagConstraints.LINE_START;
        gbl(0, 3, 1, 1);
        add(lblKostenOGrundgebuehr, gbc);
               
        JLabel anzKostenOgrundG = new JLabel();
        anzKostenOgrundG.setPreferredSize(new Dimension(70, 20));
        anzKostenOgrundG.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        gbc.anchor = GridBagConstraints.CENTER;
        gbl(1, 3, 1, 1);
        add(anzKostenOgrundG, gbc);
               
        JLabel lblKostenOgrundgEin = new JLabel(euroEin + "");
        gbc.anchor = GridBagConstraints.LINE_START;
        gbl(2, 3, 1, 1);
        add(lblKostenOgrundgEin, gbc);

//Differenz Vorjahr ohne Grundgebuehr
        JLabel anzDiffVjOgrundg = new JLabel();
        anzDiffVjOgrundg.setPreferredSize(new Dimension(70, 20));
        anzDiffVjOgrundg.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        gbc.anchor = GridBagConstraints.CENTER;
        gbl(3, 3, 1, 1);
        add(anzDiffVjOgrundg, gbc);
               
        JLabel lblDiffVjOgrundgEin = new JLabel(euroEin + "");
        gbc.anchor = GridBagConstraints.LINE_START;
        gbl(4, 3, 1, 1);
        add(lblDiffVjOgrundgEin, gbc);
               
//Aktueller Rechnungsbetrag
        JLabel lblAktKosten = new JLabel("Akt. Kosten(Brutto):");
        gbc.anchor = GridBagConstraints.LINE_START;
        gbl(0, 4, 1, 1);
        add(lblAktKosten, gbc);
       
        JLabel anzAktKosten = new JLabel();
        anzAktKosten.setPreferredSize(new Dimension(70, 20));
        anzAktKosten.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        gbc.anchor = GridBagConstraints.CENTER;
        gbl(1, 4, 1, 1);
        add(anzAktKosten, gbc);
       
        JLabel lblAktKostenEin = new JLabel(euroEin + "");
        gbc.anchor = GridBagConstraints.LINE_START;
        gbl(2, 4, 1, 1);
        add(lblAktKostenEin, gbc);
       
//Differenz Vorjahr
        JLabel anzDifferenzVJ = new JLabel();
        anzDifferenzVJ.setPreferredSize(new Dimension(70, 20));
        anzDifferenzVJ.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        gbc.anchor = GridBagConstraints.CENTER;
        gbl(3, 4, 1, 1);
        add(anzDifferenzVJ, gbc);
       
        JLabel differenzVjEin = new JLabel(euroEin + "");
        gbc.anchor = GridBagConstraints.LINE_START;
        gbl(4, 4, 1, 1);
        add(differenzVjEin, gbc);
       
//Action und Eingabe
        JLabel lblZaehlerstandEingabe = new JLabel("Zählerstand:");
        gbc.anchor = GridBagConstraints.LINE_START;
        gbl(0, 5, 1, 1);
        add(lblZaehlerstandEingabe, gbc);
       
        JTextField tFzaehlerstandEingabe = new JTextField();
        tFzaehlerstandEingabe.setBackground(UIManager.getColor("Button.background"));
        tFzaehlerstandEingabe.setPreferredSize(new Dimension(80, 20));
        AbstractDocument doc = (AbstractDocument) tFzaehlerstandEingabe.getDocument();
        doc.setDocumentFilter(new IntegerFilter());
        gbc.anchor = GridBagConstraints.CENTER;
        gbl(1, 5, 1, 1);
        add(tFzaehlerstandEingabe, gbc);
       
        JLabel lblZaehlerstandEingabeEin = new JLabel(kwhEin);
        gbc.anchor = GridBagConstraints.LINE_START;
        gbl(2, 5, 1, 1);
        add(lblZaehlerstandEingabeEin, gbc);
       
               
//Button Aufruf verrechnen()
        JButton btnOk = new JButton("OK");
        gbc.anchor = GridBagConstraints.CENTER;
        gbl(1, 6, 1, 1);
        gbc.ipadx = 30;
        gbc.ipady = 3;

        btnOk.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
//                zaehlerstandEingabe = Double.parseDouble(tFzaehlerstandEingabe.getText());
//                verrechnen();
//                anzAktKosten.setText(aktKosten + "");
//                anzDifferenzVJ.setText(differenzVJ + "");
//                anzAktStand.setText(aktStand + "");
//                anzKostenOgrundG.setText(kostenOGrundg + "");
//                anzDiffVjOgrundg.setText(diffVJoGrundg + "");
            }
        });
       
       
        // Mit Enter auslössen
        tFzaehlerstandEingabe.addKeyListener(new KeyListener() {
            @Override
            public void keyTyped(KeyEvent e) {              
            }
            @Override
            public void keyReleased(KeyEvent e) {
            }          
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode()==KeyEvent.VK_ENTER) {
                    zaehlerstandEingabe = Double.parseDouble(tFzaehlerstandEingabe.getText());
                    Datenbank db = new Datenbank();
                    db.setStromEingabe(zaehlerstandEingabe);
                    System.out.println("In StromPanel " + zaehlerstandEingabe);
                    db.verrechnen();
//                    verrechnen();
//                    anzAktKosten.setText(aktKosten + "");                  
//                    anzDifferenzVJ.setText(differenzVJ + "");
//                    anzAktStand.setText(aktStand + "");
//                    anzKostenOgrundG.setText(kostenOGrundg + "");
//                    anzDiffVjOgrundg.setText(diffVJoGrundg + "");
                }              
            }
        });
                       
        add(btnOk, gbc);  
    }
   
}

Es funktioniert auch so weit. Nur weiß ich nicht wie ich eine 2. SELECT Anweisung angeben kann.
Und wie ich dann im Anschluss das Label in StromPanel setten soll.

Und die insert() will auch noch nicht, weiß auch nicht ob ich das mit der Transaction richtig gemacht habe.

Diese Tabellen habe ich erstellt:
Code:
CREATE TABLE vertragsDaten (
    VertragsDatenId INTEGER PRIMARY KEY,
       Kwh_netto REAL NOT NULL
);




INSERT INTO verbrauchKosten (
    Eingabe_Zaehlerstand,
    Akt_Kosten,
    ZstndEndeZeitr)

VALUES(
    000000,
    00.00,
    114893
    );


    INSERT INTO vertragsDaten (
    Kwh_netto
    )
VALUES(
    10.50
    );
 

MasterShredder

Aktives Mitglied
So, hallo @mihe7.
Versuchen wir es anders: modelliere die Anwendung einmal ohne GUI.
Ich habe mal etwas gebastelt🔧. Hoffe es ist etwas geworden:

Java:
package verbrauchsrechner;
import java.util.Scanner;

public class VKonsole {
    
        
    public static void main(String[] args) {
        
        //Scanner Objekt gibt Warnung aus: Resource leak: 'scanner' is never closed
        Scanner scanner = new Scanner(System.in);
        Funktionen funk = new Funktionen();
                
        System.out.println("Bitte Wert eingeben");
        double eingabe = scanner.nextDouble();
        funk.aktStand(eingabe);
        funk.kosten();
        funk.kostenVJ();
        System.out.println("Zählerstand: " + funk.zaehlerSt + funk.kwhEin + "\t"
                            + "Stand Rechnungszeitraum: " + funk.aktStand+ funk.kwhEin);
        
        System.out.println("Kosten O. Grundg.: " + funk.kostenOGrundg + funk.euroEin + "\t"
                            + " Akt. Kosten " + funk.aktKosten + funk.euroEin);
        
        System.out.println("Differenz Vorjahr: " + funk.differenzVJ + funk.euroEin + "\t"
                            + "Diff. Vorjahr o. Grund.: " + funk.diffVJoGrundg + funk.euroEin);       
//       
    }

}

Java:
package verbrauchsrechner;

public class Funktionen {
    private static double PREISKWH=23.54, ABRECHNUNGSZEITRAUM=114893, GRUNDGEBUEHR=81.81, VORJHBETRAG=398.23, VORJHBETRAGOGRUND=257.29;
    public double aktStand, zaehlerSt, aktKosten, differenzVJ, kostenOGrundg, diffVJoGrundg;
    
    //Einheiten
    public String kwhEin="kWh",euroEin="\u20AC";
    
    
    public double aktStand(double eingabe) {
        this.zaehlerSt = eingabe;       
        this.aktStand = zaehlerSt - ABRECHNUNGSZEITRAUM;
                
        return aktStand;
        
    }
    
    public void kosten() {
        this.kostenOGrundg = Math.round(aktStand * PREISKWH / 100);
        this.aktKosten = Math.round(kostenOGrundg + GRUNDGEBUEHR * 1.19);
    }
    
    public void kostenVJ() {
        this.differenzVJ = Math.round(aktKosten - VORJHBETRAG);
        this.diffVJoGrundg = Math.round(kostenOGrundg - VORJHBETRAGOGRUND);
        
    }
    
    

}

Die Konstanten müsste man vielleicht noch in "normale" Attribute umandeln da sie ja keine Konstanten mehr sind.

Aber sonnst hoffe ich, dass ich die Aufgabe richtig verstaden und umgesetzt habe.
 

MasterShredder

Aktives Mitglied
Ist dies vielleicht besser? Habe das Scanner Objekt in einen "try Block" gesetzt war ein Schnellkorrektur Vorschlag von Eclipse.
Java:
package verbrauchsrechner;
import java.util.Scanner;

public class VKonsole {
   
       
    public static void main(String[] args) {
       
        //Scanner Objekt gibt Warhinweis aus: Resource leak: 'scanner' is never closed; Durch try Block erledigt
        try(Scanner scanner = new Scanner(System.in)) {
            Funktionen funk = new Funktionen();
                   
            System.out.println("Bitte Wert eingeben");
            double eingabe = scanner.nextDouble();
            funk.aktStand(eingabe);
            funk.kosten();
            funk.kostenVJ();
            System.out.println("Zählerstand: " + funk.zaehlerSt + funk.kwhEin + "\t"
                                + "Stand Rechnungszeitraum: " + funk.aktStand+ funk.kwhEin);
           
            System.out.println("Kosten O. Grundg.: " + funk.kostenOGrundg + funk.euroEin + "\t"
                                + " Akt. Kosten " + funk.aktKosten + funk.euroEin);
           
            System.out.println("Differenz Vorjahr: " + funk.differenzVJ + funk.euroEin + "\t"
                                + "Diff. Vorjahr o. Grund.: " + funk.diffVJoGrundg + funk.euroEin);  
        }
       
    }

}
 

mihe7

Top Contributor
Das ist schon mal besser (wobei ich nur nach dem Modell gefragt habe, den Code hätte es also gar nicht gebraucht) aber Du denkst noch zu prozedural.

Da wir jetzt die GUI endlich los sind, können wir uns auf das eigentliche Problem konzentrieren. Deine DB-Tabellen gehen wesentlich mehr in die Richtung, die man hier in Form von Klassen sehen möchte: Vertragsdaten, Ableseinformationen usw.

Ich würde in etwa so anfangen (mal rein spekulativ, weil ich nicht genau weiß, was am Ende für eine Software rauskommen soll):
  1. Ich lese einen Zähler ab und notiere mir a) welchen Zähler (z. B. Gas, Wasser, Strom), b) Datum, c) Zählerstand
  2. Es können beliebige viele Ablesungen zu beliebigen Zeitpunkten vorgenommen werden.
  3. Der Ist-Verbrauch kann zwischen zwei Ablesezeitpunkten bestimmt werden. Daraus können Durchschnittswerte pro Tag errechnet und für beliebig viele Tage angesetzt werden.
  4. Ich habe einen Vertrag mit einem Versorger über die Lieferung von Gas, Wasser oder Strom ab einem bestimmten Zeitpunkt.
  5. Es gelten gewisse Preise (Grundpreis, Arbeitspreis) ab einem bestimmten Datum.
Da würde ich unmittelbar einmal folgende Klassen (Typen) ableiten:

a) Ablesung (Produkt, Datum, Zählerstand)
b) Vertrag (Versorger, Produkt, Vertragsbeginn)
c) Tarif (gültig ab Datum, Grundpreis, Arbeitspreis)

Natürlich brauchst Du noch etwas, wo alle Ablesungen hinterlegt sind, nennen wir das einfach mal Ablesungen, und einen Verbrauchsrechner, der z. B. eine (womöglich fiktive) Abrechnung auf Grundlage der Ablesungen und Tarife ausspuckt. Eine Abrechnung könnte man als Zeitraum, Verbrauch und Endpreis darstellen (wenn man es genauer haben will, könnte man noch den verwendeten Tarif mit aufführen, dann müsste man ggf. mehrere Einträge haben). Jetzt kann man sich überlegen, welche Klasse welche Methoden anbietet und wie die Klassen zueinander in Beziehung stehen. Für eine einfache Implementierung muss man nicht alles vom Anwender definierbar machen, da reicht es, wenn man beispielsweise alles bis auf die Ablesungen im Code vorgibt.
 

MasterShredder

Aktives Mitglied
Das ist schon mal besser... ...aber Du denkst noch zu prozedural
Ja das kann gut sein😄. Ich habe noch nicht so viel Erfahrung, sodass ich wüsste was alles möglich wäre.

Ich würde in etwa so anfangen...
Ja, dies trifft zu.
Da würde ich unmittelbar einmal folgende Klassen (Typen) ableiten:

a) Ablesung (Produkt, Datum, Zählerstand)
b) Vertrag (Versorger, Produkt, Vertragsbeginn)
c) Tarif (gültig ab Datum, Grundpreis, Arbeitspreis)
Ja da würde ich auch so zustimmen. Das ist eine gute Aufteilung. Schön Sinn gemäß. Und trifft ja auch genau so im wirklichen Vertrag zu.

Natürlich brauchst Du noch etwas, wo alle Ablesungen hinterlegt sind, nennen wir das einfach mal Ablesungen, und einen Verbrauchsrechner, der z. B. eine (womöglich fiktive) Abrechnung auf Grundlage der Ablesungen und Tarife ausspuckt.
Ja genau. Ist da eine Temporäre Speicherung der Ablesung gemeint?

Jetzt kann man sich überlegen, welche Klasse welche Methoden anbietet und wie die Klassen zueinander in Beziehung stehen.
👍

Für eine einfache Implementierung muss man nicht alles vom Anwender definierbar machen, da reicht es, wenn man beispielsweise alles bis auf die Ablesungen im Code vorgibt.
Jaaa... Aber zu einem späteren Zeitpunkt will ich dies auch noch einführen. Sollte man vielleicht beachten um es nicht zu verbauen.
 
Y

yfons123

Gast
Jaaa... Aber zu einem späteren Zeitpunkt will ich dies auch noch einführen. Sollte man vielleicht beachten um es nicht zu verbauen.
wenn dein teil der etwas tut nur objekte von typ X braucht um zu funktionieren, dann ist es wurscht ob du die objekte vom typ x hardcodest oder aus einer db holst oder einer text datei

das kannst du immer noch ändern da dein teil ja nur irgendwie objekte von dem typ braucht, wie die zusammen gebaut werden ist ja komplett irrelevant
 

mihe7

Top Contributor
Und trifft ja auch genau so im wirklichen Vertrag zu.
Das ist eine der Stärken der Objektorientierung: die reale Welt läuft recht ähnlich.

Ist da eine Temporäre Speicherung der Ablesung gemeint?
Was immer Du willst.

Die Ablesungen können in einer DB (oder Datei, Hauptspeicher, ...) gespeichert sein, der Verbrauchsrechner kann eine Methode bekommen, die eine Ablesung als Parameter bekommt und Dir unter Zuhilfenahme der gespeicherten Ablesungen eine Abrechnung erstellt. Der Rechner kann auch (alternativ oder zusätzlich, völlig egal) eine Methode bekommen, der nur einen Abrechnungszeitraum bekommt und aus den gespeicherten Ablesungen eine Abrechnung erstellt. Da kannst Du jede erdenkliche Kombination berücksichtigen, ganz wie Du möchtest.

Ich würde sagen: Methode, die eine Abrechnung anhand eines Abrechnungszeitraums und zwei Ablesungen, die nicht gespeichert sein müssen, erstellt. Damit sollte sich das meiste erschlagen lassen.

Du kannst dann z. B. eine weitere Methode schreiben, die nur einen Abrechnungszeitraum und ein Produkt bekommt. Die ermittelt dann zunächst die zwei abrechnungsrelevanten Ablesungen und ruft dann die zuvor genannte Methode auf.

Jaaa... Aber zu einem späteren Zeitpunkt will ich dies auch noch einführen. Sollte man vielleicht beachten um es nicht zu verbauen.
s. Antwort von @yfons123

Im Modell ist das bereits vorhanden, nur musst Du für eine einfache Implementierung weder eine GUI schreiben, noch das Zeug aus der DB holen. Das Prinzip hast Du selbst schon angewendet, wenn auch in etwas anderer Form:
Java:
    private static double PREISKWH=23.54, ABRECHNUNGSZEITRAUM=114893, GRUNDGEBUEHR=81.81, VORJHBETRAG=398.23, VORJHBETRAGOGRUND=257.29;
 

MasterShredder

Aktives Mitglied
Ok @mihe7 hört sich gut an.

Also ich möchte alle Daten in einer Datenbank speichern und auch von dort aus aufrufen. Da ich mit ihr ultra flexibel bin. Alles an einem Punkt habe und jeden Wert auch außerhalb meines Programmes in jeglicher Art und weiße in Beziehung bringen kann.
Außerdem kann ich jeden Wert leicht bei einer Veränderung ändern, da dies eh eine neue Zeile in der DB mit sich zieht.

Ich habe hier noch ein Paar Daten gesammelt die vorkommen.
Datensammlung.png
Mhh, hier habe ich versucht die Methoden umzusetzen(die untersten Zwei).

Ich weiß nur nicht soll ich die Daten, vom Tarif zB. als Parameter oder Klassen Variablen aufrufen?

Und wie lege ich die Rechnungen am besten an? Alles in einer Methode? Oder soll ich sie aufteilen oder irgendwie speziell anlegen?
Java:
package main;

public class Verbrauchsrechner {
    public double ermittelterVerbrauch, nettoKostenOgrundg, nettoKostenMgrundg, bruttoKostenOgrundg, bruttoKostenMgrundg;
    
    //Methode zur brechnung ausgehend von 2 Punkten(Ablesungen)
    public void zeitraumBerechnen(double zRbeginnIn, double zRendeIn) {
        double zRbeginn=zRbeginnIn, zRende=zRendeIn;
        
        double ermittelterVerbrauch = zRende - zRbeginn;
        
    }
    
    public void nettoKostenBerechnen(double verbrauchIn, double nettoArbpreisIn, double nettoGrundgebuehrIn) {
        double verbrauch=verbrauchIn, nettoArbpreis=nettoArbpreisIn, nettoGrundgebuehr=nettoGrundgebuehrIn;
        
        nettoKostenOgrundg = verbrauch * nettoArbpreis;
        nettoKostenMgrundg = verbrauch * nettoArbpreis + nettoGrundgebuehr;       
        
    }
    
    public void bruttoKostenBerechnen(double verbrauchIn, double nettoArbpreisIn, double nettoGrundgebuehrIn, double mWstIn) {
        double verbrauch=verbrauchIn, nettoArbpreis=nettoArbpreisIn, nettoGrundgebuehr=nettoGrundgebuehrIn, mWst=mWstIn;
        
        bruttoKostenOgrundg = verbrauch * nettoArbpreis * mWst;
        bruttoKostenMgrundg = verbrauch * nettoArbpreis + nettoGrundgebuehr * mWst;
        
    }
    
    
    //Mögliche Verbrauchsrechner Methode
    public void berechnen(double zRbeginnIn, double zRendeIn, double nettoArbpreisIn, double nettoGrundgebuehrIn, double mWstIn) {
        double zRbeginn=zRbeginnIn, zRende=zRendeIn, nettoArbpreis=nettoArbpreisIn, nettoGrundgebuehr=nettoGrundgebuehrIn, mWst=mWstIn;
        
        ermittelterVerbrauch = zRende - zRbeginn;
        //Netto Betrag für den gewälten Zeitraum
        nettoKostenOgrundg = ermittelterVerbrauch * nettoArbpreis;
        nettoKostenMgrundg = ermittelterVerbrauch * nettoArbpreis + nettoGrundgebuehr;
        //Brutto Betrag für den gewälten Zeitraum
        bruttoKostenOgrundg = ermittelterVerbrauch * nettoArbpreis * mWst;
        bruttoKostenMgrundg = ermittelterVerbrauch * nettoArbpreis + nettoGrundgebuehr * mWst;
        
    }
    
    
    public void verbraucherWahl(double zeitraumIn, String produktIn) {
        double zeitraum=zeitraumIn;
        String produkt=produktIn;
        
        if (produkt.equals(gas)) {
            //rufe Daten für Gas aus Datenbank auf
            berechnen(übergabe);
        }
        if (produkt.equals(strom)) {
            //rufe Daten für Strom aus Datenbank auf
            berechnen(übergabe);
            
        }
    }

}
 
Y

yfons123

Gast
mit java kannst du dir sql ergebnisse generisch in objekte umwandeln lassen ( da willst du hin ) dh es wäre sinnvoll anstatt 100 doubles als parameter zu übergeben ein objekt zu übergeben das diese werte beinhaltet und sonst nichts

also diese objekte werden nur hergenommen um daten hin und her zu schaufeln
man merkt es an deinem design dass es nötig ist für objekte als parameter da du während dem tippen erkannt hast dass die benennung keinne sinn macht, deswegen hast du auch die variablen nicht richtig ausgeschrieben

also während dem tippen hast du dich selbst bestätigt dass es so nicht sinn macht, einfach päckchen ( objekte ) vorbereiten und diese übergeben


dann kannst du auch mal ein paar test cases schreiben ob überhaupt das richtige raus kommt also mal eine test konstellation schreiben, dafür brauchst du kein test framework ( wäre halt besser ) , ein einfaches system out println würde es auch tun

dann zum code
Java:
double zRbeginn=zRbeginnIn, zRende=zRendeIn;
hier würde der deutsch lehrer mit rot an die seite "Sinn?" schreiben :D
 

mihe7

Top Contributor
Ich habe hier noch ein Paar Daten gesammelt die vorkommen.
Bitte nicht auf Sammeltour gehen, einfach darauf konzentrieren, was Du brauchst. Den Rest kannst Du später immer noch ergänzen.

Also ich möchte alle Daten in einer Datenbank speichern und auch von dort aus aufrufen.
Ja und die Gründe sind auch alle völlig ok. Die Datenbank ist jedoch - genau wie die GUI - ein Implementierungsdetail, vergiss die erstmal, Du kannst zunächst einfach mal alles im Hauptspeicher halten. Am Ende läuft das auf das hinaus, was @yfons123 geschrieben hat: die Objekte werden einfach auf die Datenbank abgebildet.

Du hast einen Anwendungskern und dort spielt die Musik. Wo die Daten herkommen, wie sie gespeichert oder angezeigt werden, spielt hier keine Rolle. Wichtig ist, ein geeignetes Modell zu haben, mit dem Du die Aufgabe lösen kannst. Wenn das passt, kannst Du eine DB dranhängen, in einer Datei speichern, auf der Konsole, in einer GUI oder als Website anzeigen -> völlig egal.

Ich weiß nur nicht soll ich die Daten, vom Tarif zB. als Parameter oder Klassen Variablen aufrufen?
Wie meinen? Mal ins Blaue hinein geraten: Tarif hat einfach Getter (und ggf. Setter) und ein Tarif-Objekt kannst Du natürlich als Parameter übergeben.

Und wie lege ich die Rechnungen am besten an?
Meinst Du die Abrechnung? Das wäre auch eine Klasse, die z. B. den Abrechnungszeitraum, den Verbrauch und den Gesamtbetrag enthält (Details nach gusto).

Apropos, weil ich es gerade genannt habe und Deinen Code sehe: Zeitraum könnte man auch als Klasse modellieren.

Kommen wir mal zur Berechnung. Ein ganz einfacher Ansatz wäre, den Tarif über einen Abrechnungszeitraum anzusetzen, das könnte der Tarif selbst ausrechnen. Den Grundpreis könnte man tagesscharf berechnen (wird, wenn ich mich jetzt richtig erinnere, auch so gemacht) und der Einfachheit halber gehen wir davon aus, dass es max. 365 Tage gibt (einen eventuellen Schalttag bekommen wir also geschenkt). Im Code könnte das dann also eine Methode in Klasse Tarif sein, die in einer ersten Skizze etwa so aussehen könnte:
Java:
public Abrechnung berechne(Zeitraum abrechnungsZeitraum, double verbrauch) {
    double anteiligerGrundpreis = berechneGrundpreis(abrechnungsZeitraum);
    return new Abrechnung(abrechnungsZeitraum, verbrauch, anteiligerGrundpreis + verbrauch * arbeitspreis);
}

Habe ich also einen Tarif, kann ich mir von diesem eine Abrechnung erstellen lassen. Das wäre aber eine ganz einfache Berechnung. Real ist das etwas komplizierter: da habe ich neben einem Abrechnungszeitraum auch noch zwei Ablesungen mit denen sich der Verbrauch im Ablesezeitraum ermitteln lässt, der dann auf den Abrechnungszeitraum umgerechnet werden muss. Das kannst Du Dir ja mal überlegen.
 

MasterShredder

Aktives Mitglied
Hallo, endlich mal wieder richtig Zeit gefunden. Aber keine Angst sitze nicht Tatenlos rum;).

mit java kannst du dir sql ergebnisse generisch in objekte umwandeln lassen ( da willst du hin )
Ja ok hört sich gut an.
Java:
double zRbeginn=zRbeginnIn, zRende=zRendeIn;
hier würde der deutsch lehrer mit rot an die seite "Sinn?" schreiben :D
Ja das muss ich zugeben ist etwas kaotisch😄. Vor allem da Zeitraum ein Wort ist😅

Die Datenbank ist jedoch - genau wie die GUI - ein Implementierungsdetail, vergiss die erstmal
Du hast einen Anwendungskern und dort spielt die Musik.
Ok habe ich verstanden.

Meinst Du die Abrechnung?
Nein, ich meinte eigentlich wie ich die ganzen Beträge ausrechne.

Java:
ermittelterVerbrauch = zRende - zRbeginn;
        //Netto Betrag für den gewälten Zeitraum
        nettoKostenOgrundg = ermittelterVerbrauch * nettoArbpreis;
        nettoKostenMgrundg = ermittelterVerbrauch * nettoArbpreis + nettoGrundgebuehr;
        //Brutto Betrag für den gewälten Zeitraum
        bruttoKostenOgrundg = ermittelterVerbrauch * nettoArbpreis * mWst;
        bruttoKostenMgrundg = ermittelterVerbrauch * nettoArbpreis + nettoGrundgebuehr * mWst;

Aber wie ich bemerke kann, sollte man dies splitten und ein eigene Klassen aufteilen.
Wo wir dann zu meiner nächsten Frage kämen. Wie groß oder klein sollte eine Klasse sein. Also wie viele Zeilen sollte Code haben um eine eigene Klasse zu bekommen? Oder Geht es nur darum in sinnvolle Bereiche aufzuteilen?
Ich denke, denke ich halt ziemlich einfach. Für mich ist da eine Zeile Subtraktion, eine weitere Multiplikation und vielleicht noch eine Addition.
Aber wie ich dies jetzt Programmiertechnisch umsetzen kann ist mir noch nicht klar😀.
 
Y

yfons123

Gast
Wo wir dann zu meiner nächsten Frage kämen. Wie groß oder klein sollte eine Klasse sein. Also wie viele Zeilen sollte Code haben um eine eigene Klasse zu bekommen? Oder Geht es nur darum in sinnvolle Bereiche aufzuteilen?
der ganze boilerplate code von java und das public private blabla und der ganze "unnötige scheiß" der bei python ja sooooooooooooooooooooooooooooooooooooooooooo gut ist dass das nicht da ist ohhh maaa gawwd python soooooo guuud

das ganze zeug ist dafür gut dass du in 1en monat auf den code schaust und dir denkst "jo kapier ich"

diese videos wo jemand "joaa da 8k zeilen C prozedurale welt generation easy" in 1 tag ( pure fiktion ohne vorwissen ) runter geschrieben hat
und einfach nur miserablen code hingepflastert hat, aber es ist komplex also ist es toll für die jungen "oh wow so komplexen code will ich auch verstehen"

( nachfolgendes kann man auch in C umsetzen )
wenn du in java die ganze verbose sache mit klassen und abstrakt und SOLID und blabla umsetzt, dann kommst du an den punkt wo du dir sagen kannst "ich muss jetzt nur noch 20 zeilen verstehen, der rest ist mir wurscht das funktioniert ja dann schon"

und dann hast du einen drastischen mehrwert

8k zeilen wirrwar mist vs 20 zeilen wirrwar mist

und die änderung an den 20zeilen zerschießt dir nicht die anderen sachen sondern nur die 20 zeilen
 

mihe7

Top Contributor
Wie groß oder klein sollte eine Klasse sein. Also wie viele Zeilen sollte Code haben um eine eigene Klasse zu bekommen? Oder Geht es nur darum in sinnvolle Bereiche aufzuteilen?

Es geht bei Klassen (bzw. Objekten) darum, sinnvolle Abstraktionen zu finden. Die Anzahl der Code-Zeilen (LoC) spielt nur die Rolle eines Indikators: je mehr Zeilen, desto höher die Wahrscheinlichkeit, dass die Klasse für zu vieles zuständig ist. Man spricht in dem Zusammenhang von Kohäsion, die den "inneren (logischen) Zusammenhalt" einer Klasse beschreibt.

Stell ich mir schon die Frage.
Das ist in Bezug auf den "Zeitraum" auch eine sehr gute Frage!

Klar, man könnte den Zeitraum auch einfach mit zwei Instanzvariablen in den diversen Klassen, in denen ein Zeitraum benötigt wird, beschreiben und natürlich könnte man zwei "Datümer" als Parameter verwenden, um einen Zeitraum zu übergeben. In diese Betrachtung geht aber nur der Datenteil ein. Was völlig fehlt ist die Semantik und das "Verhalten". Die Bedeutung würde man nur anhand der Bezeichner erahnen können: LocalDate von, LocalDate bis - ok, müsste ein Zeitraum sein. Und wenn die Bezeichner noch beschissen sind, dann wirds lustig:

Java:
LocalDate datum1, datum2, datum3, datum4;

Kann jetzt sein, dass datum1 und datum4 einen Zeitraum bilden, oder datum1 und datum2, dafür aber darum3 und darum4 unabhängig Daten sind. Zum Vergleich:

Java:
Zeitraum zeitraum1, zeitraum2;
Die Bezeichner sind genauso bescheiden aber ich sehe sofort: ok, das sind zwei Zeiträume.

Der zweite Punkt war ja das Verhalten. Nochmal zurück zu den LocalDate-Geschichten:
Java:
public double berechne(LocalDate von, LocalDate bis, ...) {
    int anzahlTage = (int) DAYS.between(von, bis);
    // ...
}

Und dann haben wir noch irgendwo eine Ausgabe z. B. für ein PDF:
Java:
public void report(LocalDate von, LocalDate bis, ...) {
    int anzahlTage = (int) DAYS.between(von, bis);
    // ...
}

Ok, kein Problem: ich berechne halt die Anzahl der Tage. Aber ich berechne sie an mehreren Stellen im Code. D. h. bei einer Änderung muss ich alle Stellen im Code finden und ebenfalls ändern und das, obwohl die Berechnung immer gleich abläuft.

Machen wir das mal anders (hier mal mit einem record statt einer class):
Java:
public record Zeitraum(LocalDate von, LocalDate bis) {
    public int anzahlTage() {
        return (int) DAYS.between(von, bis);
    }
}

Die Methoden oben sehen dann so aus:
Java:
public double berechne(Zeitraum abrechnungsZeitraum, ...) {
    int anzahlTage = abrechnungsZeitraum.anzahlTage();
    // ...
}

Java:
public void report(Zeitraum abrechnungsZeitraum, ...) {
    int anzahlTage = abrechnungsZeitraum.anzahlTage();
    // ...
}

Werden die Anzahl der Tage künftig anders gezählt, dann ändere ich nur Zeitraum. Thema erledigt.

Jetzt müsste ein Einwand kommen: Moooment, die Ermittlung der Anzahl an Tagen eines Zeitraums könnte sich ja nur für den Abrechnungszeitraum ändern, nicht aber für andere Zeiträume. Das ist völlig richtig, in meinen Modell modelliert Zeitraum aber gerade einen Abrechnungszeitraum. Sollten andere Zeiträume dargestellt werden müssen, muss das Design dahingehend angepasst werden, weil diese Abstraktion in der Form nicht mehr geeignet ist. Da gibts dann diverse Möglichkeiten (Umbenennung ggf. mit Einführung eines gemeinsamen Interfaces oder einer abstrakten Basisklasse mit zwei Subklassen, auch ein Strategy-Pattern wäre denkbar, man könnte die Berechnung auch in eine separate Klasse pflanzen, dann wäre Zeitraum nur noch ein von- und ein bis-Datum). Man sieht: Entwurfsentscheidungen haben weitreichende Konsequenzen.

Der Punkt aber ist, dass Zeitraum hier ein Typ ist, der sich um genau eines kümmert: den Abrechnungszeitraum. Nicht mehr, nicht weniger. Das macht das Handling leichter.
 
Y

yfons123

Gast
Stell ich mir schon die Frage.
Der Punkt aber ist, dass Zeitraum hier ein Typ ist, der sich um genau eines kümmert: den Abrechnungszeitraum. Nicht mehr, nicht weniger. Das macht das Handling leichter.
was du mit einer klasse machen kannst ist dass du sie dir generisch aus einen select erzeugen lassen kannst

wie zb das ist möglich
Java:
Zeitraum zeit = DB.Select<Zeitraum>("SELECT AnfangsDatum,Enddatum FROM Zeiten;")
wie auch immer deine datenbank verbindung und dein sql framework aussieht

damit hast du ein sehr einfaches handling mit daten und musst nicht mit "wo gehört jetzt der sql wert hin und wo gehört der hin" rum kämpfen

die variablen wurden jetzt schon nicht sinnvoll benannt , es war während dem coden schon nicht sinnvoll für den programmierer das so zu bauen und da ist halt das erste anzeichen von sinnlosen variablen bezeichnungen
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
S Daten aus Import Datei auslesen und sortieren Java Basics - Anfänger-Themen 2
A Daten aus einer HashMap aus einer DB speichern und mit neuen Werten vergleichen Java Basics - Anfänger-Themen 8
Mady Daten von JList & Combobox in JTable adden Java Basics - Anfänger-Themen 2
W Daten in Echtzeit übernehmen Java Basics - Anfänger-Themen 5
Z Java ArrayList speichert falsche Daten ab bzw. gibt falsche Daten aus? Java Basics - Anfänger-Themen 42
M Daten aus .txt Datei einlesen und weiterverarbeiten Java Basics - Anfänger-Themen 80
I H2 Datenbank starten / Daten in File speichern Java Basics - Anfänger-Themen 25
M Mehrere Daten/ Variablen Speichern Java Basics - Anfänger-Themen 9
E fehlermeldung bei richtigen login daten Java Basics - Anfänger-Themen 7
C Java Funktion: externe Daten vom Internet einbinden Java Basics - Anfänger-Themen 2
P Schiebefix - ArrayList überschreibt Daten Java Basics - Anfänger-Themen 3
S Daten/Klassen/Packages richtig updaten!? Java Basics - Anfänger-Themen 2
E Wie gebe ich alle Daten zwischen zwei Zeitpunkten aus? Java Basics - Anfänger-Themen 2
H Daten aus einer Datei in eine Liste speichern Java Basics - Anfänger-Themen 23
M Tabellen- Daten laden Java Basics - Anfänger-Themen 2
A Klasse um daten zu einlesen Java Basics - Anfänger-Themen 26
A Literale für primitive Daten Typen Java Basics - Anfänger-Themen 4
N Zwei Daten (Datum) miteinander vergleichen, abspeichern, laden Java Basics - Anfänger-Themen 4
A Daten auslesen/vergleichen Java Basics - Anfänger-Themen 3
D Sportwetten Daten Atomatisch analysieren um optimale Strategie zu erhalten Java Basics - Anfänger-Themen 6
S Java Daten in Excel speichern Java Basics - Anfänger-Themen 1
S Daten speichern, ohne Datenbank Java Basics - Anfänger-Themen 8
L Daten aus ArrayList in Datenbank durchsuchen Java Basics - Anfänger-Themen 5
Shallty Daten speichern und ändern? Java Basics - Anfänger-Themen 32
M Sqlite table löschen und daten einfügen Java Basics - Anfänger-Themen 5
S Binäre-Suche bei unsortierten Daten Java Basics - Anfänger-Themen 7
N Was passiert wenn wir Daten auf der Festplatte abspeichern wollen? bzgl. BufferStreams Java Basics - Anfänger-Themen 9
T Daten von Objekten speichern Java Basics - Anfänger-Themen 7
A Minesweeper - Daten Java Basics - Anfänger-Themen 46
A Eingelesene Daten in Array(Liste) abspeichern? Java Basics - Anfänger-Themen 18
S Daten aus zwei Verschiedenen Tabellen in eine ArrayListe Java Basics - Anfänger-Themen 4
WPS1000 Input/Output Wie aktiviere ich den Daten Transfer von der RS232 in meine Java Applikation Java Basics - Anfänger-Themen 2
R Eigenes Protokoll zur Übermittlung von Daten zum Webserver? Java Basics - Anfänger-Themen 4
A Reader wohin werden Daten gespeichert? Java Basics - Anfänger-Themen 7
M Erste Schritte CSV-File einlesen und Daten verarbeiten Java Basics - Anfänger-Themen 5
S Daten aus eigenständiger .class-Datei abrufen Java Basics - Anfänger-Themen 1
E Daten dem Super Aufruf übergeben Java Basics - Anfänger-Themen 3
M jTabel mit Daten Füllen Java Basics - Anfänger-Themen 5
M Wie erzeuge ich die Differenz von zwei Daten in Stunden?? Java Basics - Anfänger-Themen 2
S Daten lesen und speichern Java Basics - Anfänger-Themen 26
S JTable mit Daten füllen Java Basics - Anfänger-Themen 7
L Java Programm zum Auswerten von Daten Java Basics - Anfänger-Themen 11
H Passwortmanager, Sicherheit der Daten Java Basics - Anfänger-Themen 12
G Best Practice Wie große "Tabellen" effizient durchsuchen und Daten händeln? Java Basics - Anfänger-Themen 15
U Daten aus Datei einlesen Java Basics - Anfänger-Themen 4
M Best Practice Daten-Import /Trabsfomration aus Textdatei Java Basics - Anfänger-Themen 12
R JTable Suchfunktion mit SQL Daten Java Basics - Anfänger-Themen 2
E Daten gehen nicht in Datenbank Java Basics - Anfänger-Themen 14
M Erste Schritte Speichern von mehreren Daten Java Basics - Anfänger-Themen 3
J Daten einer Textdatei in ein JTable importieren. Java Basics - Anfänger-Themen 3
F Daten von Thread an den aufrufenden zurückgeben Java Basics - Anfänger-Themen 22
C Endlosschleife bei füllen von Daten im JTable Java Basics - Anfänger-Themen 5
N Erste Schritte Dedicated Server \ Senden und Empfangen von Daten/Befehlen Java Basics - Anfänger-Themen 2
A Probleme beim zykl. aktulisieren von Daten in JTable Java Basics - Anfänger-Themen 3
D NPE beim laden von Daten aus MySQL Java Basics - Anfänger-Themen 9
P Einlesen von Daten via BufferedReader Java Basics - Anfänger-Themen 4
P Methoden ausgelesene (CSV-) Daten in Liste einer anderen Klasse einlesen Java Basics - Anfänger-Themen 0
F Daten aus Excel-Tabelle in Java importieren Java Basics - Anfänger-Themen 15
F Http Post von mehreren Daten Java Basics - Anfänger-Themen 5
F Daten auf Webserver laden - wiederholen bei Fehler Java Basics - Anfänger-Themen 0
W Best Practice problemabhängige Persistentmachung von Daten Java Basics - Anfänger-Themen 6
P Daten von Internetseite auslesen Java Basics - Anfänger-Themen 10
N Daten/Formular per POST an Firefox/Browser senden Java Basics - Anfänger-Themen 7
D Daten mit Apache POI in eine Excel Datei schreiben Java Basics - Anfänger-Themen 5
T JTable Daten aus txt datei Java Basics - Anfänger-Themen 3
T printf Daten aus der Tabelle in Excel übernehmen Java Basics - Anfänger-Themen 5
P zweidimensionales Array anlegen und mit DB-Daten füllen Java Basics - Anfänger-Themen 14
V Einlesen von Daten Java Basics - Anfänger-Themen 8
J TableView zeigt keine Daten an Java Basics - Anfänger-Themen 14
J Daten im Programm speichern Java Basics - Anfänger-Themen 14
N Interface Daten einem Implementierten Interface zuweisen Java Basics - Anfänger-Themen 37
O Probleme mit CSV Daten Java Basics - Anfänger-Themen 10
M Arrays: Trennung von Daten und Darstellung Java Basics - Anfänger-Themen 1
S Daten aus Array in Klasse übertragen Java Basics - Anfänger-Themen 12
M Wie sicher sind Daten im Java Programm? Java Basics - Anfänger-Themen 9
R Daten via Post an php Script senden Java Basics - Anfänger-Themen 1
B Probleme bei "Daten in CSV File schreiben". Java Basics - Anfänger-Themen 9
C Datei mit Daten einlesen und höchsten wert der zweiten Spalte ermitteln Java Basics - Anfänger-Themen 1
W (XML/XSL) Daten aus Eclipse in eine Klasse Laden. Java Basics - Anfänger-Themen 1
I Daten speichern ohne Datenbank Java Basics - Anfänger-Themen 20
D Daten von einem int in einen string Java Basics - Anfänger-Themen 5
L Daten aus Array Feld löschen Java Basics - Anfänger-Themen 2
T Input/Output Daten/Objekte einfach speichern Java Basics - Anfänger-Themen 5
IngoF GUI mit Thread Daten austauschen. Java Basics - Anfänger-Themen 6
S Daten aus anderen Dateien in neue Datei einlesen Java Basics - Anfänger-Themen 3
fLooojava Daten im selben Netzwerk an IP Java Basics - Anfänger-Themen 1
M Junit Tests durchführen, die eine Verbindung zu einer Daten erfordern Java Basics - Anfänger-Themen 3
K HashMap mit Daten aus ArrayList befüllen Java Basics - Anfänger-Themen 14
P Daten auslesen und in CSV speichern Java Basics - Anfänger-Themen 6
J Daten aus zweiter Klasse importieren Java Basics - Anfänger-Themen 33
C Daten speichern und laden Java Basics - Anfänger-Themen 6
S Je nach erhaltene Daten unterschiedlich reagieren (Design Pattern?) Java Basics - Anfänger-Themen 3
J Daten von einer PHP Datei ablesen Java Basics - Anfänger-Themen 1
B Klassen Zugriff auf Daten der Child-Klasse Java Basics - Anfänger-Themen 9
K Daten (im Sinne von Datum) aus Webseiten extrahieren Java Basics - Anfänger-Themen 6
S Erste Schritte Tage zwischen 2 Daten berechnen Java Basics - Anfänger-Themen 6
A daten vom 1d array in 2d matrix speichern Java Basics - Anfänger-Themen 3
R csv-Datei auslesen und ausgelesene Daten in neue csv-Datei speichern Java Basics - Anfänger-Themen 2
Z Differenz zwischen 2 Daten berechnen, ohne importiere Funktionen! Java Basics - Anfänger-Themen 10
A Datum zwischen zwei Daten berechnen und in Tagen anzeigen Java Basics - Anfänger-Themen 4

Ähnliche Java Themen

Neue Themen


Oben