Ergebnisse in csv schreiben

Fragen zu Tkinter.
Antworten
v1000
User
Beiträge: 3
Registriert: Samstag 29. Oktober 2022, 10:55

Sehr geehrte Damen und Herren,
ich bin Neuling in Python, lese und probiere viel, aber ich finde nicht den richtigen Hinweis, um bei meinem Versuch weiter zu kommen.
Bestimmt hat einer von Ihnen einen Lösungsvorschlag.

Mein Code:
from tkinter import *
from tkinter import StringVar
from tkinter.ttk import Combobox
import csv

def berechnen():
Höhe = float(Hoe.get())

Seitenlänge = Höhe

result1.set("%.2f" % Seitenlänge)

if __name__ == "__main__":
root = Tk()
root.title("blabla 1.0")

Hoe = StringVar()
result1 = StringVar()

label2 = Label(text="Höhe").grid(row=2)
Höhe = Entry(root, textvariable=Hoe).grid(row=2, column=1)


label7 = Label(text="Seitenlänge").grid(row=7)
labelresult1 = Entry(root, textvariable=result1, bg="lightgrey").grid(row=7, column=1)

farbe = []
with open("Farben.txt") as inFile:
farbe = [line for line in inFile]

# label Material
Label(text="Farbe").grid(row=1, column=3)

# Combobox erstellen
n = StringVar()
fa_select = Combobox(textvariable=n)

# Farben laden
fa_select["values"] = tuple(farbe)
fa_select.grid(row=1, column=4)
fa_select.current()

# Combobox erstellen
n = StringVar()
fa_select = Combobox(textvariable=n)

Berechnen = Button(root, text="berechnen", command=berechnen)
Berechnen.grid(row=11, column=5, padx=5, pady=5)

Beenden = Button(root, text="beenden & csv", command=root.destroy)
Beenden.grid(row=13, column=5, padx=5, pady=5)

with open("Liste.csv", "w", newline="") as file:
writer = csv.writer(file)
writer.writerow(["Pos.", "Länge","Farbe"])
writer.writerow([1, result1, fa_select])


mainloop()
Hier komme ich nicht weiter:
writer.writerow([1, result1, fa_select])

Im Voraus besten Dank.
Freue mich über jeden Hinweis.
Mit freundlichen Grüßen
v1000
Benutzeravatar
__blackjack__
User
Beiträge: 13533
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@v1000: Sternchen-Importe sind Böse™. Da holt man sich gerade bei `tkinter` fast 140 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.

Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.

Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (PascalCase).

Namen sollten keine kryptischen Abkürzungen enthalten oder gar nur daraus bestehen. Der Name soll dem Leser vermitteln was der Wert dahinter im Programm bedeutet, nicht zum rätseln zwingen.

Man nummeriert keine Namen. Dann will man sich entweder bessere Namen überlegen, oder gar keine Einzelnamen/-werte verwenden, sondern eine Datenstruktur. Oft eine Liste.

GUI-Elemente würde ich in der Reigenfolge anlegen in der sie auch in der GUI angezeigt werden. Es ist so schon nicht so einfach sich über den Code die GUI vorzustellen, das wird nicht besser wenn die Reihenfolge im Code scheinbar gar keinen Zusammenhang mit der Reihenfolge in der GUI hat.

Beim `grid()` sollte man nicht so grosszügig freie Zeilen und Spalten lassen. Wie das angezeigt wird, also ob und wie viel Platz freie Zeilen und Spalten haben, ist von der Plattform abhängig. Das ist also kein robuster Weg um Platz in der GUI zu lassen.

An einige Namen wird sinnloserweise der Rückgabewert von `grid()` gebunden. Der ist `None`. Immer.

`n` und `fa_select` werden zweimal erstellt, aber nur einmal verwendet. Beides sind keine guten Namen, weil sie kryptische Abkürzungen enthalten bzw. im Fall von `n` nur eine kryptische Abkürzung ist. `n` geht gerade mal so als Name für eine ganze Zahl, die eine Anzahl beschreibt, obwohl das auch schon recht ”mathematisch” ist, aber das ist sicher kein sinnvoller Name für ein `StringVar`-Objekt das einen Farbnamen enthält.

`farbe` steht nicht für *eine* Farbe, sondern für mehrere Farben. Die Zuweisung einer leeren Liste ist unnötig, die wird ja überhaupt nicht verwendet. Die „list comprehension“ ist so ein bisschen sinnlos weil die nur die Elemente aus der Datei in die Liste kopiert. Entweder macht man das kürzer durch einen Aufruf von `list()`, oder man macht tatsächlich etwas sinnvolles in der Comprehension — zum Beispiel die Zeilenenden entfernen.

Der `current()`-Aufruf macht an der Stelle so keinen Sinn.

Beim öffnen von Textdateien sollte man immer explizit die Kodierung angeben.

Funktionen (und Methoden) bekommen alles was sie benötigen als Argument(e) übergeben. `berechnen()` braucht also die beiden `StringVar`-Objekte die darin verwendet werden. Bei sehr einfachen GUI Programmen kommt man manchmal mit `functools.partial()` aus, aber für jede nicht-triviale GUI kommt man um objecktorientierte Programmierung (OOP) nicht herum. Also eigene Klassen schreiben.

`Seitenlänge` ist überflüssig. Ab da ist der selbe Wert unter zwei Namen verfügbar. Da der erste nicht mehr benutzt wird, hätte man gleich `seitenlaenge` als Namen verwenden können.

Den ``%``-Operator würde ich nicht mehr zum formatieren von Werten in Zeichenketten verwenden. Dafür gibt es die `format()`-Methode auf Zeichenketten und ab Python 3.6 f-Zeichenkettenliterale.

Das schreiben der CSV-Datei passiert an der falschen Stelle. Vor dem `mainloop()`-Aufruf macht das keinen Sinn. Da war die GUI ja noch gar nicht aktiv und der Benutzer hatte noch gar keine Chance irgend etwas einzugeben oder auszuwählen. Laut Beschriftung der Schaltflächen müsste das in einer Funktion/Methode passieren, die aufgerufen wird, wenn man den „beenden & CSV“-Knopf drückt.

Und dann kann man keine `StringVar`-Objekte oder GUI-Elemente in einer Datei schreiben. Da muss Code stehen der die Werte aus diesen Objekten holt.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
import csv
import tkinter as tk
from functools import partial
from tkinter import ttk


def beenden(root, result_var, farbe_var):
    with open("Liste.csv", "w", encoding="utf-8", newline="") as file:
        csv.writer(file).writerows(
            [
                ["Position", "Länge", "Farbe"],
                [1, result_var.get(), farbe_var.get()],
            ]
        )
    root.quit()


def main():
    with open("Farben.txt", encoding="utf-8") as lines:
        farben = [line.strip() for line in lines]

    root = tk.Tk()
    root.title("blabla 1.0")

    hoehe_var = tk.StringVar()
    result_var = tk.StringVar()
    farbe_var = tk.StringVar()

    tk.Label(text="Farbe").grid(row=1, column=3)

    ttk.Combobox(textvariable=farbe_var, values=farben).grid(row=1, column=4)

    tk.Label(text="Höhe").grid(row=2, column=0)
    tk.Entry(root, textvariable=hoehe_var).grid(row=2, column=1)

    tk.Label(text="Seitenlänge").grid(row=3, column=0)
    tk.Entry(root, textvariable=result_var, bg="lightgrey").grid(
        row=3, column=1
    )

    tk.Button(
        root,
        text="berechnen",
        command=lambda: result_var.set(f"{float(hoehe_var.get()):.2f}"),
    ).grid(row=4, column=5, padx=5, pady=5)

    tk.Button(
        root,
        text="CSV schreiben & beenden",
        command=partial(beenden, root, result_var, farbe_var),
    ).grid(row=5, column=5, padx=5, pady=5)

    root.mainloop()


if __name__ == "__main__":
    main()

Code: Alles auswählen

- (void)countSheep {
    unsigned int sheep = 0;
    while ( ! [self isAsleep]) { ++sheep; }
}
v1000
User
Beiträge: 3
Registriert: Samstag 29. Oktober 2022, 10:55

Sehr geehrter black jack,
vielen Dank für ihre Mühe.
Ich habe den Code getestet und bin begeistert :D .
Super, das einem Anfänger so umfangreich geholfen wird und nicht auf irgendwelche Links verwiesen wird, lies mal das schau mal hier....
Sehr konstruktiv, jetzt kann ich vergleichen und evtl. verstehen.
VIELEN DANK
Grüße v1000
v1000
User
Beiträge: 3
Registriert: Samstag 29. Oktober 2022, 10:55

Sehr geehrte Damen und Herren,

nachdem ich am Code weiter gemacht habe, stehe ich vor folgender Frage: Wie kann ich mit meinem Button "Berechnen" mehrere Berechnungen durchführen?
In meinem Beispiel möchte ich von Maß_A Maß_B subtrahieren, das wiederum soll meine Seitenbreite werden.
In meinem ersten Versuch hatte ich folgendes probiert:

Code: Alles auswählen

def berechnen():
Höhe = float(Hoe.get())

Berechnen = Button(root, text="berechnen", command=berechnen)

Code: Alles auswählen

import csv
import tkinter as tk
from functools import partial
from tkinter import ttk


def beenden(root, seitenlaenge_var, seitenbreite_var, farbe_var):
    with open("Liste.csv", "w", encoding="utf-8", newline="") as file:
        csv.writer(file).writerows(
            [
                ["Position", "Länge", "Breite", "Farbe"],
                [1, seitenlaenge_var.get(), seitenbreite_var, farbe_var.get()],
            ]
        )
    root.quit()


def main():
    with open("Farben.txt", encoding="utf-8") as lines:
        farben = [line.strip() for line in lines]

    root = tk.Tk()
    root.title("blabla 1.0")

    hoehe_var = tk.StringVar()
    seitenlaenge_var = tk.StringVar()
    seitenbreite_var = tk.StringVar()
    mas_a_var = tk.StringVar()
    mas_b_var = tk.StringVar()
    farbe_var = tk.StringVar()

    tk.Label(text="Farbe").grid(row=1, column=3)

    ttk.Combobox(textvariable=farbe_var, values=farben).grid(row=1, column=4)

    tk.Label(text="Maß_A").grid(row=2, column=0)
    tk.Entry(root, textvariable=mas_a_var).grid(row=2, column=1)

    tk.Label(text="Maß_B").grid(row=3, column=0)
    tk.Entry(root, textvariable=mas_b_var).grid(row=3, column=1)

    tk.Label(text="Höhe").grid(row=4, column=0)
    tk.Entry(root, textvariable=hoehe_var).grid(row=4, column=1)

    tk.Label(text="Seitenlänge").grid(row=5, column=0)
    tk.Entry(root, textvariable=seitenlaenge_var, bg="lightgrey").grid(row=5, column=1)

    tk.Label(text="Seitenbreite").grid(row=6, column=0)
    tk.Entry(root, textvariable=seitenbreite_var, bg="lightgrey").grid(row=6, column=1)

    tk.Button(
        root,
        text="berechnen",
        command=lambda: seitenlaenge_var.set(f"{float(hoehe_var.get()):.2f}"),
    ).grid(row=4, column=5, padx=5, pady=5)

    tk.Button(
        root,
        text="CSV schreiben & beenden",
        command=partial(beenden, root, seitenlaenge_var, farbe_var),
    ).grid(row=5, column=5, padx=5, pady=5)

    root.mainloop()


if __name__ == "__main__":
    main()
    
Im Voraus besten Dank.
Freue mich über jeden Hinweis.
Mit freundlichen Grüßen
v1000
Benutzeravatar
__blackjack__
User
Beiträge: 13533
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@v1000: Mit `beenden()` gibt es doch bereits eine Funktion die mehr als eine Sache macht. Wobei das nach den Änderungen so nicht mehr funktionieren wird, und es sieht nicht so aus, als wären Problem und Lösung beim Schreiben der CSV-Datei aus dem ersten Beitrag wirklich verstanden worden.

Code: Alles auswählen

- (void)countSheep {
    unsigned int sheep = 0;
    while ( ! [self isAsleep]) { ++sheep; }
}
Antworten