Datenaustausch unter Klassen - GUI

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Hartmannsgruber
User
Beiträge: 47
Registriert: Mittwoch 15. Januar 2014, 22:30
Wohnort: Bad Kötzting
Kontaktdaten:

Donnerstag 18. Juni 2020, 08:26

Servus Forum,

ich komme momentan nicht weiter.
Habe zwei Bücher zur Fehlersuche, sowie mehrere Stunden Internet zu rate gezogen und finde keine Lösung.

Fehlerbeschreibung:
Das "Programm" erledigt die bis zum jetzigen Punkt geschriebenen Sachen.
Perfekt programmiert ist es aber wohl kaum.

Es sind zwei Fehler die ich nicht lösen kann.
1. Wenn im GUI die Schaltflächen "Statistik anzeigen", sowie "Bestellung anzeigen" gedrückt werden,
wird jeweils ein neues Fenster erzeugt. In diesen neuen Fenstern wird aber links oben ein Knopf angezeigt
der hier nichts verloren hat.

2. Das ist jetzt mein schwerwiegenderes Problem. Über die beiden Schaltflächen "Statistik anzeigen" und "Bestellung anzeigen"
wird jeweils ein neues Fenster geöffnet, welches ein Kind von Mainwidow ist. Da der Aritkelbestand sich aber in der Elternklasse
befindet, weiß ich nicht wie ich diesen auch von den Kindern aufrufbar/bearbeitbar machen kann.
Der Interpreter meldet mir beim aufruf der Funktion "Statistik anzeigen", dass er im __init__ zwei "Argumente" übergeben haben möchte.
Dies ist zwar verständlich warum, aber woher soll ich die nehmen?

Code: Alles auswählen

#!/usr/bin/python3
# -*- coding: utf-8 -*-

import sys
import csv
import re
import ast
import json
import datetime

from collections import OrderedDict
from PyQt5 import QtCore
from PyQt5.QtCore import QCoreApplication
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout, \
                            QHBoxLayout, QLineEdit, QPushButton, QTextEdit, \
                            QCompleter, QTableWidget, QTableWidgetItem, \
                            QInputDialog, QMessageBox, QAbstractItemView, \
                            QTreeView, QComboBox, QFormLayout


class Lager():
    def __init__(self):
        self.artikelbestand = OrderedDict()
        # Beinhaltet alle eingelesen Artikel aus der Csv Datei im Format
        # OrderedDict(Artikelnummer : {"Artikelbezeichnung": "str",
        # "Menge": "int", "Einheit": "str", "VPE": "int",
        # "E.-Pr.Ne": "float", "Steuersatz" : "float", "E.-Pr. Br." : "float",
        # "Geb.-Pr. Ne." : "float", "Geb.-Pr. Br" : "float",
        # "Lieferant" : "str", "Artikelnummer" : "int",
        # "Bestellstatus" : "bool", "Bestellmenge" : "int" }
        
        self.feldnamen = [] # Benötigt zur Erstellung der Feldnamen der Tabelle
 
    def artikel_aus_csv_laden(self, csvdatei):
    # Einlesen von Dateien aus der übergeben CSV Datei
        with open(csvdatei, "r", encoding="utf-8", newline="") as csvfile:
            reader =  csv.DictReader(csvfile, delimiter=";")
            self.feldnamen = reader.fieldnames
            # Es werden die Feldnamen der CSV Datei in die Instanzvariable
            # self.feldnamen übergeben. Diese werden später in der Funktion
            # tabelle_erzeugen gebraucht, um die Header Labels des Tabellenwid -
            # gets zu beschriften.
            
            reader = sorted(reader, key=lambda d: d["Artikelbezeichnung"])
            # Die einzelnen Zeilen des readerobjects werden nach ihren Namen
            # sortiert, damit immer eine Alphabetische Reihenfolge unabhängig
            # von der Eintragung in die CSV Datei vorliegt. Die Artikelnummern
            # Können daher durcheinander sein.

            vortlaufendenummer = 1
            # Zähler der die Artikelnummer des einzelnen Artikels festlegt und
            # die Maximale Anzahl aller Dateien in der CSV Datei erfasst.

            meldung_auf_konsole_ausgeben("folgende Artikel wurden aus der CSV "\
                                         "Datei eingelesen")

            for zeile in reader:
                zeile = {k:v if v != "" else "0" for (k,v) in zeile.items()}
                # Es wird jede Zeile geprüft, ob sich darin leere Zellen befin -
                # den und diese dann mit einer 0 im Stringformat aufgefüllt.
                # Das Stringformat ist wichtig, da wenn er in einer Zelle einge-
                # fügt wird auf die später die int() funktion angewandt wird
                # erscheint eine Fehlermeldung.

                zeile["Menge"] = float(zeile["Menge"].replace(",","."))
                zeile["VPE"] = int(zeile["VPE"])
                zeile["E.-Pr. Ne."] = float(zeile["E.-Pr. Ne."]\
                                            .replace(",","."))
                zeile["Steuersatz"] = float(zeile["Steuersatz"]\
                                            .replace(",","."))
                zeile["E.-Pr. Br."] = float(zeile["E.-Pr. Br."]\
                                            .replace(",","."))
                zeile["Geb.-Pr. Ne."] = float(zeile["Geb.-Pr. Ne."]\
                                              .replace(",","."))
                zeile["Geb.-Pr. Br."] = float(zeile["Geb.-Pr. Br."]\
                                              .replace(",","."))
                zeile["Artikelnummer"] = int(zeile["Artikelnummer"])
                zeile["Bestellstatus"] = ast.literal_eval(zeile\
                                                          ["Bestellstatus"])
                zeile["Bestellmenge"] = int(zeile["Bestellmenge"])
                # Es werden die jeweiligen Zellen in bestimmte Formate forma -
                # tiert umd diese später besser bearbeiten zu können.
        
                self.artikelbestand[vortlaufendenummer] = OrderedDict(zeile)
                # Dem OrderedDict wird ein Schlüssel/Wert - Paar hinzugefügt.
                # Format -> Vortlaufendenummer : {}
                # Die Vortlaufendenummer dient als interne Artikelnummer.
                # Die Artikelnummern dienen nur zur einzigartigen Durchnum -
                # merierung, sie werden nicht zur Artikelsuche benötigt.
                
                print(self.artikelbestand[vortlaufendenummer])
                # Nur zum Debuggen
                                
                vortlaufendenummer += 1
            
    def artikel_in_csv_schreiben(self, tabelle, csvdatei, feldnamen):
    # Speichern der Werte aus der übergebenen Tabelle in die angegebene CSV -
    # Datei. Es werden alle Zeilen der Tabelle neu gschrieben, nicht nur die
    # die sich geändert haben.
        
        with open(csvdatei, "w", newline="", encoding="utf-8") as csvfile:
            writer = csv.writer(csvfile, delimiter=";")
            writer.writerow(feldnamen)
            # Als erste Zeile werden die Feldnamen in die CSV-Datei geschrieben

            for zeile in tabelle:
                writer.writerow(tabelle[zeile].values())
                
    
class Zulieferer():
    def __init__(self):
        self.lieferanten = OrderedDict()
        # Beinhaltet alle Angaben zu den Lieferanten aus der in die CSV Datei
        # erhaltenen Werte im Format:
        # OrderedDict(Vortlaufendenummer : {'Name': 'str',
        # 'Strasse': 'str', 'Hausnummer': 'str', 'PLZ': 'int',
        # 'Ort': 'str', 'Telefonnummer': 'int', 'Email': 'str',
        # 'Kundennummer': 'int'})
        
        self.feldnamen = []
        # self.feldnamen enthalten die Feldnamen aus der eingelesenen CSV Datei

    def zulieferer_aus_csv_laden(self, csvdatei):
    # Einlesen von Dateien aus der übergeben Csv Datei
        with open(csvdatei, "r", encoding="utf-8", newline="") as datei:
            reader =  csv.DictReader(datei, delimiter=";")
            self.feldnamen = reader.fieldnames
            # Es werden die Feldnamen der CSV Datei in die Instanzvariable
            # self.feldnamen übergeben. Diese werden später in der Funktion
            # tabelle_erzeugen gebraucht, um die Header Labels des Tabellenwid -
            # gets zu beschriften.
            
            reader = sorted(reader, key=lambda d: d["Name"])
            # Die einzelnen Zeilen des readerobjects werden nach dem Namen des
            #Lieferanten sortiert, damit immer eine Alphabetische Reihenfolge
            # unabhängig von der Eintragung in die CSV Datei vorliegt. Die Namen
            # Können daher durcheinander sein.
            
            vortlaufendenummer = 1

            meldung_auf_konsole_ausgeben("folgende Lieferanten wurden aus der "\
                                         "CSV Datei eingelesen")
            for zeile in reader:
                self.lieferanten[vortlaufendenummer] = zeile
                # Dem OrderedDict wird ein Schlüssel/Wert - Paar hinzugefügt.
                # Format -> Vortlaufendenummer : {}
                # Die Vortlaufendenummer dient als interne Lieferantennummer.
                # Die Lieferantennummern dienen nur zur einzigartigen Durchnum -
                # merierung, sie werden nicht zur Lieferantensuche benötigt.
                
                print(self.lieferanten[vortlaufendenummer])
                # Nur zum Debuggen
                
                vortlaufendenummer += 1

    def zulieferer_in_csv_schreiben(csvdatei):
        pass
    

class Mainwindow(QWidget):
    def __init__(self, lager, zulieferer):
        super().__init__()

        self.lager = lager
        self.zulieferer = zulieferer
        
        self.fenstereinstellungen()
        self.erzeugeWidgets()
        self.erzeugeLayout()
        self.autovervollstaendigung()
        self.show()

        
    def fenstereinstellungen(self):
        self.resize(1500, 600)
        self.setWindowTitle("Bestellung V 1.0")

        
    def erzeugeWidgets(self):
        self.label1 = QLabel()

        self.tablewidget = QTableWidget()
        self.tablewidget.setEditTriggers(QTreeView.NoEditTriggers)
        self.tablewidget.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.tablewidget.setSelectionMode(QAbstractItemView.SingleSelection)
        
        self.suchleiste = QLineEdit(self)
        self.suchleiste.returnPressed.connect(lambda: self.artikel_suchen_und_anzeigen("Artikelbezeichnung"))
        self.suchleiste.setToolTip("Artikelbezeichnung, oder Artikelnummer "\
                                   "eingeben")
        
        self.sf_suche = QPushButton("Suchen", self)
        self.sf_suche.clicked.connect(lambda: self.artikel_suchen_und_anzeigen("Artikelbezeichnung"))
        
        self.sf_bestellen = QPushButton("Artikel bestellen", self)
        self.sf_bestellen.clicked.connect(self.artikel_bestellen)

        self.sf_bestellung = QPushButton("Bestellung anzeigen", self)
        self.sf_bestellung.clicked.connect(self.bestellung_fenster_oeffnen)

        self.sf_statistik = QPushButton("Statistik anzeigen", self)
        self.sf_statistik.clicked.connect(self.statistik_fenster_oeffnen)

        self.sf_ende = QPushButton("Beenden", self)
        self.sf_ende.clicked.connect(self.fenster_schliessen)

        
    def erzeugeLayout(self):
        vbox1 = QVBoxLayout()
        vbox1.addWidget(self.label1)
        vbox1.addWidget(self.tablewidget)
        
        hbox1 = QHBoxLayout()
        hbox1.addWidget(self.suchleiste)
        hbox1.addWidget(self.sf_suche)

        hbox2 = QHBoxLayout()
        hbox2.addWidget(self.sf_bestellen)
        hbox2.addWidget(self.sf_bestellung)
        hbox2.addWidget(self.sf_statistik)
        hbox2.addWidget(self.sf_ende)

        masterbox = QVBoxLayout()
        masterbox.addLayout(hbox1)
        masterbox.addLayout(vbox1)
        masterbox.addLayout(hbox2)
        self.setLayout(masterbox)

        
    def tabelle_erzeugen(self, artikelnummernliste):

        self.tablewidget.setColumnCount(len(self.lager.feldnamen))

        self.tablewidget.setHorizontalHeaderLabels(self.lager.feldnamen)

        self.tablewidget.setRowCount(len(artikelnummernliste))

        zeile = -1

        meldung_auf_konsole_ausgeben("folgende Artikel wurden in die Tabelle" \
                                     " geschrieben")

        for artikelnummer in artikelnummernliste:
            zeile += 1
            spalte = 0

            print(self.lager.artikelbestand[artikelnummer])
            # Nur zur Fehlersuche, gibt alle gefundenden Einträge aus dem
            # OrderedDict auf der Konsole aus.

            for schluessel in self.lager.artikelbestand[artikelnummer]:
                self.tablewidget.setItem(zeile, spalte, \
                                         QTableWidgetItem(str(self.lager.\
                                            artikelbestand[artikelnummer]\
                                                        [schluessel])))

                spalte += 1

        self.label1.setText("Es wurden " + str(len(artikelnummernliste)) + \
                            " Artikel gefunden")

        
    def artikel_suchen_und_anzeigen(self, feldfilter):
        # Es wird in der Instanz der Klasse "Lager" nach den eingegebenen Text-
        # teilen in den angegebenen Feldnamen hier genannt "feldfilter" gesucht
        # und gibt diese dann durch aufruf der tabelle_erzeugen funktion aus.

        durchlaufzaehler = 0

        suchbegriff = "".join(["[" + str(zeichen).upper() +\
                               str(zeichen).lower() + "]"\
                               for zeichen in self.suchleiste.text()])
        # Formatieren der eingegebenen Zeichenkette von Brot -> [Bb[Rr][Oo][Tt]

        meldung_auf_konsole_ausgeben("Die Suche nach der Zeichenkette" \
                                        " ergab folgende Nummern")
        print("Gesuchte Zeichenkette: " + suchbegriff)

        gefundene_artikelnummern = []
        # Behälter für alle Artikelnummern bei denen die gesuchte Zeichenfolge
        # passt.
        
        for artikelnummer in self.lager.artikelbestand:
            if re.findall(suchbegriff, self.lager.artikelbestand\
                          [artikelnummer][feldfilter]):
                gefundene_artikelnummern.append(artikelnummer)
            # Durchsuchen aller Artikelbezeichnungen, ob der Suchbegriff darin
            # vorkommt. Passt der Suchbegriff, wird dessen Artikelnummer in die
            # Liste gefundene_Artiklnummern geschrieben um damit die entsprech-
            # ende Tabelle zu füllen
            
            durchlaufzaehler += 1
        print("Artikelnummern in denen die gesuchte Zeichenkette vorkommt: " +
              str(gefundene_artikelnummern))
        # Ausgabe zur möglichen Fehlersuche

        self.tabelle_erzeugen(gefundene_artikelnummern)


    def artikel_bestellen(self):
    #
    # Auswahl der zu bestellenden Menge die dem Artikel hinterlegt werden soll  

        artikelauswahl = self.tablewidget.selectedItems()
        
        if artikelauswahl != []:
        # Prüfung ob aus der Tabelle eine Zeile angewählt wurde 

            bestellmenge, check = QInputDialog.getInt(self, "Bestellmenge",
                                           "Zu bestellenden Menge eingeben:",
                                                      value=1, min=0)
            # Aufruf einer Dialogbox, bei der die gewünschte Bestellmenge ausge-
            # wählt werden kann und der Variable "bestellmenge" übergeben wird
            
            if check:
            # Abfrage ob "Ok" im Abfragefeld ausgewählt wurde
 
                for artikelnummer in self.lager.artikelbestand:
                # Es werden alle Artikelnummern die sich im Container
                # self.warenbestand.lager nacheinander aufgerufen.

                    if self.lager.artikelbestand[artikelnummer]\
                       ["Artikelbezeichnung"] == artikelauswahl[0].text():
                    # Wird der Artikelname gefunden, der zur Auswahl 
                    # passt wird die alte Bestellmenge auf die neu eingegebene
                    # gesetzt und der Bestellstatus auf True gesetzt.
    
                        self.lager.artikelbestand[artikelnummer]\
                                                ["Bestellmenge"] = bestellmenge

                        if bestellmenge != 0:
                        # Es wird geprüft, ob die eingebenen Zahl den Wert
                        # ungleich 0 aufweist, dann wird der Bestellstatus auf
                        # "Wahr" gesetzt. Andernfalls, ist die Bestellmenge 0,
                        # so wird der Bestellstatus auf "Falsch" gesetzt, da ja
                        # Auch keine Menge des Artikels mehr benötigt wird.

                            self.lager.artikelbestand[artikelnummer]\
                                ["Bestellstatus"] = True
                        else:
                            self.lager.artikelbestand[artikelnummer]\
                                ["Bestellstatus"] = False

                        meldung_auf_konsole_ausgeben("Es wurde die "\
                            "Bestellmenge " + str(bestellmenge) + \
                            " zum Artikel \"" + self.lager.artikelbestand\
                            [artikelnummer]["Artikelbezeichnung"] +
                            "\" hinzugefügt")       
                        # Ausgabe auf der Konsole, nur zur Fehlersuche
                        
                        self.tabelle_erzeugen(list(range(1,len(\
                                                self.lager.artikelbestand)\
                                                         +1)))

                        self.lager.artikel_in_csv_schreiben(
                            self.lager.artikelbestand,\
                            "./Listen/Artikelliste.csv",\
                            self.lager.feldnamen)
                        
                        break
            
        else:
            print("es wurde KEIN Artikel ausgewählt!")
            QMessageBox.information(self, "Auswahl", "Um eine Bestellmenge"\
                                        " hinzufügen zu können bitte erst"\
                                        " einen Artikel aus der Tabelle"\
                                    "auswählen!") 
    
        
    def autovervollstaendigung(self):
        autocomplete = QCompleter([self.lager.artikelbestand[nummer]["Artikelbezeichnung"] for nummer in self.lager.artikelbestand])
        self.suchleiste.setCompleter(autocomplete)
       
                
    def bestellung_fenster_oeffnen(self):
        self.bestellfenster = Bestellwindow()

    def statistik_fenster_oeffnen(self):
        self.statistikfenster = Statistikwindow()  

    def fenster_schliessen(self):
        reply = QMessageBox.question(self, "Achtung", "Möchten Sie die "\
                                     "Anwendung wirklich beenden?", \
                                     QMessageBox.Yes | QMessageBox.No, \
                                     QMessageBox.No)
        
        if reply == QMessageBox.Yes:
            QCoreApplication.quit()

            
class Bestellwindow(Mainwindow):
    def __init__(self):
        Mainwindow.__init__(self)

    def fenstereinstellungen(self):
        self.setWindowTitle("Bestellung nach Lieferant")
        self.resize(500, 600)
        
    def erzeugeWidgets(self):
        Mainwindow.erzeugeWidgets(self)
        self.label1.setText("Lieferant auswählen:")

        self.cb_lieferanten = QComboBox()
        
        self.sf_senden = QPushButton("Bestellung senden", self)
        #self.sf_senden.click.connect(self.bestellung_an_lieferanten_senden)
        
    def erzeugeLayout(self):
        hbox1 = QHBoxLayout()
        hbox1.addWidget(self.label1)
        hbox1.addWidget(self.cb_lieferanten)

        hbox2 = QHBoxLayout()
        hbox2.addWidget(self.sf_senden)
        hbox2.addWidget(self.sf_ende)

        masterbox = QVBoxLayout()
        masterbox.addLayout(hbox1)
        masterbox.addWidget(self.tablewidget)
        masterbox.addLayout(hbox2)
        self.setLayout(masterbox)

    def bestellung_an_lieferanten_senden(self):
        pass
        
    def fenster_schliessen(self):
        self.close()
        
        
class Statistikwindow(Mainwindow):
    def __init__(self):
        super().__init__()

    def fenstereinstellungen(self):
        self.setWindowTitle("Bestellstatistiken")
        self.resize(800, 600)
        
    def erzeugeWidgets(self):
        super().erzeugeWidgets()
        self.label_artikelname = QLabel()
        self.label1.setText("Statistik zum Artikel:")
                
    def erzeugeLayout(self):
        hbox1 = QHBoxLayout()
        hbox1.addWidget(self.suchleiste)
        hbox1.addWidget(self.sf_suche)

        hbox2 = QHBoxLayout()
        hbox2.addWidget(self.label1)
        hbox2.addWidget(self.label_artikelname)
        
        masterbox = QVBoxLayout()
        masterbox.addLayout(hbox1)
        masterbox.addLayout(hbox2)
        masterbox.addWidget(self.tablewidget)
        masterbox.addWidget(self.sf_ende)
        self.setLayout(masterbox)

    def fenster_schliessen(self):
        self.close()

        
def meldung_auf_konsole_ausgeben(text):
    print("-" * (len(text)+4))
    print("| " + text + " |")
    print("-" * (len(text)+4))

    
def main():
    lager = Lager()
    lager.artikel_aus_csv_laden("./Listen/Artikelliste.csv")
    
    zulieferer = Zulieferer()
    zulieferer.zulieferer_aus_csv_laden("./Listen/Lieferantenliste.csv")

    app = QApplication(sys.argv)       
    mw = Mainwindow(lager, zulieferer)
    mw.tabelle_erzeugen(tuple(mw.lager.artikelbestand.keys()))
    sys.exit(app.exec_())

    
if __name__ == "__main__":
    main()
Über Hilfe wäre ich sehr dankbar.
__deets__
User
Beiträge: 8275
Registriert: Mittwoch 14. Oktober 2015, 14:29

Donnerstag 18. Juni 2020, 09:37

- mainwindow sollte auch von QMainWindow erben
- die Fensterposition kann Qt sich selbst merken und wiederherstellen. Das solltest du benutzen, statt das zu erzwingen.
- statt muehselig den ganzen Code fuer die UI-Elemente zu schreiben, benutz den Qt Designer, und lade die ui-Dateien. Das reduziert den Code auf einen Bruchteil.
- das das Statistikwindow von Mainwindow erbt ist konzeptionell falsch und offenbart, dass du da noch nicht verstanden hast, wie Vererbung und Komposition zueinander stehen. Ein Objekt einer Unterklasse B hat nicht magisch den Zustand eines ANDEREN Objektes der Oberklasse von B.
- wenn du einem Objekt Zugriff auf Dinge geben willst, dann musst du die dem bekanntmachen. zB indem du sie einfach per Konstruktor uebergibst:

Code: Alles auswählen

    def statistik_fenster_oeffnen(self):
        self.statistikfenster = Statistikwindow(ding_das_das_statistik_fenster_braucht)
Dazu muss das Statisikwindow natuerilch entsprechend angepasst werden, das es das Argument uebernimmt und was damit anstellt. Nochmal: Vererbung bewegt nicht magisch Zustand durch die Gegend, und das ist auch in keinem Tutorial so gezeigt worden.
- die ganzen relativen Pfade fallen dir irgendwann auf die Fuesse, und hart kodiert sollten sie auch nicht einfach irgendwo mitten im Quellcode stehen.
- statt meldung_auf_konsole_ausgeben benutz einfach das existierende logging-Modul und konfigurier das mit logging.basicConfig, ggf. in Abhaengigkeit von Kommandozeilen-Argumenten.
- warum rufst du tabelle_erzeugen nicht auch im Konstruktor auf, warum passiert das *nach* der Anlage von Maindwindow?
- statt tausend mal replace(",", ".") zu betreiben, mach das entweder einmal *vor* dem Verarbeiten einer Zeile, oder wenigstens in einer Funktion item2float oder aehnlichem.
- statt die ganzen Schluessel auf beiden Seiten zu wiederholen, schreib einmal

Code: Alles auswählen

for name in ["VPE", ...]:
      zeile[name] = item2float(zeile[name])
Schon dutzende Zeilen gespart.

- Kommentare schreibt man *vor* das Ding, das sie Beschreiben, oder in die gleiche Zeile. Nicht dahinter.

Nachtrag: die Vererbung ist auch Ursache deines ersten Problems. Lass das einfach.
Hartmannsgruber
User
Beiträge: 47
Registriert: Mittwoch 15. Januar 2014, 22:30
Wohnort: Bad Kötzting
Kontaktdaten:

Donnerstag 18. Juni 2020, 13:01

vielen Dank für die Rückmeldung.
Warum soll hier die Vererbung unterlassen werden?
Es sind Funktionen, sowie die Schaltflächen die von allen Fenstern verwendet werden.
Diese müssten ja dann bei jeder Klasse neu definiert werden, obwohl sie das gleiche machen.

Da ich noch am Lernen und Üben bin, schreibe ich die UI-Elemente gerne um diese mir zu merken
und zu verstehen. Wenn ich Übung darin habe stelle ich gerne auf den Qt Designer um.
Ich beschäftige mich erst seit ein paar Wochen intensiver mit Objekten und deren Vererbung.
Damit ich dies irgendwann beherrsche, halte ich mich an "learning by doing".

Ich habe übersehen, dass ich beim Aufruf der Fenster nicht die benötigten Dinge mit übergeben habe.
Nachdem ich die Antwort gelesen habe ist mir mein Fehler sofort aufgefallen und klar gewesen. :D

Wie meinst du das mit den relativen Pfaden?
Ich habe nachgelesen was hart kodiert ist, bräuchte aber zum besseren Verständnis ein kleines Beispiel.

Ich rufe tabelle_erzeugen nicht im Konstruktor auf, da sonst aufgrund der Vererbung dies ebenfalls
ausgeführt wird sobald ich ein neues Fenster öffne. Ein neues Fenster sollte ja standardmässig leer sein
und auf die Eingaben des Benutzers warten.
Den Import mit den etlichen replace baue ich um, ist logisch. :wink:
Benutzeravatar
__blackjack__
User
Beiträge: 6366
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Donnerstag 18. Juni 2020, 13:33

@Hartmannsgruber: Nein, da wird eben nichts von den anderen Fenstern verwendet, beziehungsweise das was da war, eine Schaltfläche, wolltest Du ja gar nicht. Es ist schlicht falsch. Die beiden anderen Fenster *sind* *keine* Hauptfenster.

Zu `Lager` und damit auch zu `Lieferanten` hatte ich in einem anderen Thema ja schon mal was gesagt. Auch zu der Aufteilung der `__init__()` in verschiedene Methoden und was das für blöde Folgen hat. Und das sich Widgets nicht selbst anzeigen, also der `show()`-Aufruf von ausserhalb passiert und nicht in der eigenen `__init__()`.
long long ago; /* in a galaxy far far away */
__deets__
User
Beiträge: 8275
Registriert: Mittwoch 14. Oktober 2015, 14:29

Donnerstag 18. Juni 2020, 14:04

Hartmannsgruber hat geschrieben:
Donnerstag 18. Juni 2020, 13:01
vielen Dank für die Rückmeldung.
Warum soll hier die Vererbung unterlassen werden?
Es sind Funktionen, sowie die Schaltflächen die von allen Fenstern verwendet werden.
Diese müssten ja dann bei jeder Klasse neu definiert werden, obwohl sie das gleiche machen.
Wenn es solche Dinge gibt, dann kann man das auch anders loesen, durch Funktioenen oder wenn es denn wirklich Sinn machen *wuerde* (was ich hier nicht sehe) mit einer gemeinsamen Basisklasse.

Hartmannsgruber hat geschrieben:
Donnerstag 18. Juni 2020, 13:01
Wie meinst du das mit den relativen Pfaden?
Ich habe nachgelesen was hart kodiert ist, bräuchte aber zum besseren Verständnis ein kleines Beispiel.
Mittem im Quelltext stehen Pfade, die auch noch relativ sind. Wehe, du startest dein Programm mal aus einem anderen Verzeichnis. Oder man will es mal befaehigen, zu laden und zu speichern. Oder einer der Dateinamen aendert sich, aber du machst es nur an einer Stelle.
Hartmannsgruber hat geschrieben:
Donnerstag 18. Juni 2020, 13:01
Ich rufe tabelle_erzeugen nicht im Konstruktor auf, da sonst aufgrund der Vererbung dies ebenfalls
ausgeführt wird sobald ich ein neues Fenster öffne. Ein neues Fenster sollte ja standardmässig leer sein
und auf die Eingaben des Benutzers warten.
Und genau das ist der Grund, warum man nicht vererbt: du arbeitest *aktiv* gegen deine eigenen Klassen an, weil die Basisklasse etwas beinhaltet, das die Unterklasse gar nicht braucht. Womit das ganze Konstrukt fragil und undurschaubar wird.
Hartmannsgruber
User
Beiträge: 47
Registriert: Mittwoch 15. Januar 2014, 22:30
Wohnort: Bad Kötzting
Kontaktdaten:

Dienstag 30. Juni 2020, 13:42

@__deets__
Und genau das ist der Grund, warum man nicht vererbt: du arbeitest *aktiv* gegen deine eigenen Klassen an, weil die Basisklasse etwas beinhaltet, das die Unterklasse gar nicht braucht. Womit das ganze Konstrukt fragil und undurschaubar wird.
Ist meine daraus gezogene Schlussfolgerung richtig, dass man Vererbung nur verwendet, wenn die Kindelemente zu 100% den Aufbau der Elternelemente benötigen / verwenden können.
Sollte sich der Fall für Vererbung ergeben, wird eine ganz grobe Elternklasse erstellt und diese wird dann mit den Kindern immer weiter "verfeinert"?


@__blackjack__
Auch zu der Aufteilung der `__init__()` in verschiedene Methoden und was das für blöde Folgen hat.
Ich habe diesen Aufbau aus dem Buch von Michael Weigend. Er baut in seinen Beispielen die GUI mit PyQt so auf, dass er das in der __init__ aufteilt.
Ist dies nun nicht richtig, bzw. was können sich daraus für Folgen ergeben?
Benutzeravatar
__blackjack__
User
Beiträge: 6366
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Dienstag 30. Juni 2020, 14:24

@Hartmannsgruber: Durch die Aufteilung wird es unübersichtlicher, man muss mehr Attribute an das Objekt binden als tatsächlich am Ende gebraucht werden, und es ist halt so überhaupt nicht die Aufteilung die man braucht, wenn man Teile daraus in eine eigene Klasse herausziehen möchte. Oder wenn man das gar nicht mehr in Code schreibt sondern als *.ui-Datei zur Laufzeit lädt.
long long ago; /* in a galaxy far far away */
Antworten