@SnuSnu: An dem Quelltext fällt als erstes mal auf, dass Du keine Funktionen benutzt, denn ``def`` alleine reicht nicht um eine richtige Funktion zu schreiben. Funktionen und Methoden bekommen alles was sie ausser Konstanten benötigen als Argument(e) übergeben. Man verwendet keine globalen Variablen.
Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.
Funktions- und Methodennamen werden üblicherweise nach der Tätigkeit benannt die sie durchführen, damit der Leser weiss was sie tun und sie leicht(er) von eher passiven Werten unterscheiden zu können.
Die `info()`-”Funktion” verwendet `trv`, `wrapper6`, `mydb`, und `cursor` einfach so auf magische Weise aus der ”Umgebung”.
`cursor` sollte aber gar nicht von aussen kommen. Die sind als eher kurzlebige Objekte gedacht, die man erstellt, eine Operation damit ausführt, und sie dann wieder schliesst.
Falls `Label` durch einen Sternchen-Import zustande gekommen ist: Sternchen-Importe sind Böse™. Da holt man sich gerade bei `tkinter` fast 200 Namen ins Modul von denen nur ein kleiner Bruchteil verwendet wird. Auch Namen die gar nicht in `tkinter` definiert werden, sondern ihrerseits von woanders importiert werden. Das macht Programme unnötig unübersichtlicher und fehleranfälliger und es besteht die Gefahr von Namenskollisionen.
Namen sollten keine kryptischen Abkürzungen enthalten, oder gar nur daraus bestehen. `trv` sollte mindestens `treeview` heissen (vermute ich). Besser wäre wenn an dem Namen auch ablesbar wäre was für Informationen darin enthalten sind.
Man nummeriert keine Namen. Da will man sich entweder bessere, passendere Namen ausdenken, oder man möchte gar keine Einzelnamen sondern eine Datenstruktur. Oft eine Liste. Innderhalb der Funktion macht die 6 in `wrapper6` überhaupt gar keinen Sinn. Und der konventionelle, generische Name für diesen Wert ist `master`. Falls man mit dem Begriff `master` Probleme hat, ist auch `parent` üblich.
Manchmal will man bei nummeriert oder sonstwie schlechten Namen auch gar keine(n) Namen verwenden. Wie bei den ganzen nummerierten `query_label`-Namen, denn die werden streng genommen nirgends verwendet, wenn man das Zwischenergebnis nicht unbedingt unnötigerweise an einen Namen binden will. Da könnte man auch einfach das hier schreiben:
Code: Alles auswählen
tk.Label(master, text="Lieferant:", font=10).place(x=10, y=50)
tk.Label(master, text="Kontakt1:", font=10).place(x=10, y=87)
tk.Label(master, text="Telefonnummer1:", font=10).place(x=10, y=122)
tk.Label(master, text="Kontakt2:", font=10).place(x=10, y=157)
tk.Label(master, text="Telefonnummer2:", font=10).place(x=10, y=194)
tk.Label(master, text="Straße:", font=10).place(x=10, y=231)
tk.Label(master, text="PLZ:", font=10).place(x=10, y=269)
tk.Label(master, text="Ort:", font=10).place(x=10, y=307)
tk.Label(master, text="EMAIL:", font=10).place(x=10, y=339)
tk.Label(master, text="Web:", font=10).place(x=10, y=374)
Wobei man `place()` nicht verwendet. Ist Dir da nicht selbst aufgefallen wie bekloppt und aufwändig das ist da für jede Textzeile die `y`-Position auszurechnen oder durch ausprobieren heraus zu finden? So eine Tabelle baut man am einfachsten mit `grid()` auf und das dann mit einer Schleife die Beschriftungen und Werte zusammenführt.
Dann braucht man `print_records` nicht. Das hätte man aber auch nicht so aufwändig zusammengestückelt, sondern `str()` auf alle Elemente angewendet und mit der `join()`-Methode verbunden, dann ist das ganze ein kurzer Einzeiler:
Und das ganze ausserhalb einer Schleife, weil absolut keinen Sinn macht das für jedes Element in `info_l` zu wiederholen, also 10 mal den *gleichen* Wert zusammen zu setzen. Es reicht wenn man das *einmal* macht.
Statt die kompletten Informationen zu denen es Artikel gibt abzufragen und daraus dann einen *zufälligen* Wert heraus zu picken, kann man die Abfrage gleich mit LIMIT auf einen Datensatz eingrenzen. Warum zufällig? Nun, die SELECT-Abfrage hat kein Sortierkriterium, also ist die Reihenfolge in der die Datensätze geliefert werden undefiniert. Selbst wenn es sortiert wäre, ist dieses Vorgehen mehr als komisch. Denn Fall „Selektiere alle Datensätze nach Datum aufsteigend und gib mir davon den n-ten Datensatz“ mit Variablen `n` hat man in der Praxis nicht. Da machst Du irgendwas falsch.
Was soll das `my` bei `mydb`? Gibt es auch eine `our_db` oder eine `their_db`? Falls nein, ist das ein sinnloser Zusatz der dem Leser nichts bringt. Da sollte man lieber `database` aussschreiben oder es `db_connection` nennen.
Das PRAGMA macht nicht was Du denkst was es macht. Damit schaltet man ein ob SQLite bei INSERT/UPDATE prüft ob dadurch im Schema angegebene Fremdschlüssel-Constraints verletzt werden. Bei SELECT kann man keine Fremdschlüssel-Constraints verletzten. So ein Pragma würde man auch nicht in beliebigen Funktionen/Methoden setzen, sondern einmal direkt nach dem erstellen der Datenbankverbindung. Das auf Funktions- oder Methodenebene zu machen macht vielleicht Sinn wenn man grosse Datenmengen einfügt von denen man sicher ist, dass sie die Fremdschlüssel-Constraints nicht verletzen.
Das ``return`` am Ende der Funktion ist Überflüssig.
Bliebe von dem Code das hier übrig:
Code: Alles auswählen
import tkinter as tk
from contextlib import closing
from functools import partial
def display_info(master, db_connection, _event=None):
with closing(db_connection.cursor()) as cursor:
cursor.execute(
"SELECT Firma, Kontaktperson1, Telefonnummer1, Kontaktperson2,"
" Telefonnummer2, Straße, PLZ, Ort, EMail, WEB"
" FROM information"
" INNER JOIN artikel"
" ON information.LieferantenID = artikel.LieferantenID"
" LIMIT 1"
)
row = cursor.fetchone()
db_connection.commit()
print(row)
for row_index, (label_text, value) in enumerate(
zip(
[
"Lieferant",
"Kontakt1",
"Telefonnummer1",
"Kontakt2",
"Telefonnummer2",
"Straße",
"PLZ",
"Ort",
"Email",
"Web",
],
row,
)
):
tk.Label(
master, text=f"{label_text}: ", font=10, foreground="red"
).grid(column=0, row=row_index, sticky=tk.E)
tk.Label(master, text=value, font=10).grid(
column=1, row=row_index, sticky=tk.W
)
def main():
...
treeview.bind(
"<ButtonRelease 1>",
partial(display_info, wrapper6, database),
)
Die Funktion verwendet das `treeview`-Objekt jetzt gar nicht mehr weil der Code effektiv ja sowieso *irgendeinen* Datensatz abgefragt hat, die Auswahl im Treeview also gar keine wirkliche Rolle gespielt hat. Sollte sie wohl. Ich vermute mal sehr stark in Form einer Bedingung beim SELECT. Nur welche?
Und das erstellen der `Label` in der Funktion ist problematisch und deshalb ungewöhnlich, weil man die Funktion so nur ein einziges mal aufrufen kann. Wenn man das mehrfach tut werden immer mehr und mehr `Label`-Objekte erstellt und übereinander gestapelt.
GUIs baut man in der Regel einmal am Anfang komplett auf und aktualisiert dann die angezeigten Werte. Die Beschriftungen hätten in der Funktion also gar nichts zu suchen und man würde die bereits woanders *einmal* erstellten `Label`-Objekte, beispielsweise in Form einer Liste, an die Funktion übergeben, und die würde dann die Texte der Labels durch die Werte aus dem Datensatz ersetzen.