TK-Button führt Aktion bei Programmstart aus, anstatt bei Betätigung

Fragen zu Tkinter.
Antworten
Adn110
User
Beiträge: 3
Registriert: Sonntag 13. März 2022, 23:41

Hallo zusammen,

ich möchte mir gerade ein Karteikartensystem programmieren und wollte dabei auf das tkinter package zurückgreifen.
Eigentlich möchte ich in die beiden Entryfelder jeweils etwas schreiben und diese 2 Begriffe dann durch Knopfdruck mit Fach (=1) und Datum in meine .txt-Datei schreiben.

Wie bereits gesagt, wird mein zweiter Button (button2) immer bei Programmstart ausgeführt, die Betätigung danach hat keine Auswirkungen mehr.
Der erste Button funktioniert dagegen einwandfrei.

Der Umweg über die Funktion "aktion" war ein verzweifelter Versuch, also davon nicht ablenken lassen ;-)

Code: Alles auswählen

from datetime import date
import tkinter as tk


def NeueKarte(datei, r, l):
    datumd = date.today()
    datum = datumd.strftime("%d-%m-%Y")
    kastenw = open(datei, "a+")
    kastenw.write(r + " # " + l + " # 1 # " + datum + "\n")
    kastenw.close()


def aktion():
    print(text1.get())
    NeueKarte("kasten.txt", text1.get(), text2.get())
    text1.delete(0,tk.END)
    text2.delete(0,tk.END)


root = tk.Tk()
root.geometry("1500x1300+30+30")

ueberschrift1 = tk.Label(root, text="Bitte gib deine Fragen ein", bg="orange").place(x=5, y=5, width=160, height=25)
ueberschriftf = tk.Label(root, text="Frage", bg="orange").place(x=25, y=50, width=160, height=25)
ueberschrifta = tk.Label(root, text="Antwort", bg="orange").place(x=635, y=50, width=160, height=25)

text1 = tk.Entry(root)
text1.place(x=20, y=80, width=600, height=300)
text2 = tk.Entry(root)
text2.place(x=630, y=80, width=600, height=300)

button1 = tk.Button(root, text="Ich bin fertig", command=root.destroy)
button1.place(x=1300, y=200, width=120, height=25)
button2 = tk.Button(root, text="Wort", command=aktion())
button2.place(x=1300, y=150, width=120, height=25)

root.mainloop()
Benutzeravatar
sparrow
User
Beiträge: 4165
Registriert: Freitag 17. April 2009, 10:28

"action()" ist nicht "action".
"action()" führt die Funktion aus und das Ergebnis ist, was die Funktion zurück gibt. (in deinem Fall "None", weil du nichts explizit zurück gibst).
"action" ist die Funktion.

Ketzt kannst du dir überlegen, was an den Button gebunden werden soll: Der Rückgabewert der ausgeführten Funktion - oder die Funktion.
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

Benutze keine kryptischen Abkürzungen. Warum hängt an `datumd` ein d? Was soll bei kastenw das w? Warum eine Überschriftf?
Variablennamen müssen sprechend sein, und nicht zum Rätseln einladen.
r und l sind noch schlimmer, wobei es keinen schlimmeren Variablennamen als l gibt, weil man den leicht mit 1 oder I verwechseln kann.
Benutze keine globalen Variablen. Alles was eine Funktion braucht, muß sie über ihre Argumente bekommen. Bei `aktion` sind das text1 und text2.

In `NeueKarte` stückelst Du Strings per + zusammen. Statt dessen verwendet man Formatstrings. # als Trennzeichen ist ungewöhnlich. Datum formatiert man entweder Deutsch: dd.mm.yyyy oder in der Internationalen Variante yyyy-mm-dd (englisch würde man wohl eher nicht wählen, weil da nie klar ist, ob Monat oder Tag zuerst kommt).
Dateien öffnet man innerhalb eines with-Statements und der Filemode "a+" ist eigentlich nie sinnvoll; das muß "a" sein.

Es fehlt das Hauptprogramm (main), um zu verhindern, dass Du aus Versehen globale Variablen definierst.
`ueberschrift1`, `ueberschrifta` und `ueberschriftf` sind wenig sinnvolle Variablen, weil sie alle nur recht umständlich mit None initialisiert werden, dann aber nicht weiter benutzt werden.

`place` darf man bei GUIs nicht benutzen, weil sie je nach System zu unbenutzbaren Oberflächen führen.

Code: Alles auswählen

from datetime import date
import tkinter as tk
from functools import partial

def write_new_card(filename, question, answer):
    today = date.today()
    with open(filename, "a") as file:
        file.write(f"{question} # {answer} # {today:%Y-%m-%d}\n")


def aktion(text1, text2):
    print(text1.get())
    write_new_card("kasten.txt", text1.get(), text2.get())
    text1.delete(0,tk.END)
    text2.delete(0,tk.END)


def main():
    root = tk.Tk()
    tk.Label(root, text="Bitte gib deine Fragen ein", bg="orange").grid(row=0, column=0)
    tk.Label(root, text="Frage", bg="orange").grid(row=1, column=0)
    tk.Label(root, text="Antwort", bg="orange").grid(row=1, column=1)

    text1 = tk.Entry(root)
    text1.grid(row=2, column=0)
    text2 = tk.Entry(root)
    text2.grid(row=2, column=1)

    button1 = tk.Button(root, text="Ich bin fertig", command=root.destroy)
    button1.grid(row=3, column=0)
    button2 = tk.Button(root, text="Wort", command=partial(aktion, text1, text2))
    button2.grid(row=3, column=1)

    root.mainloop()

if __name__ == "__main__":
    main()
Adn110
User
Beiträge: 3
Registriert: Sonntag 13. März 2022, 23:41

sparrow hat geschrieben: Montag 14. März 2022, 08:54 "action()" ist nicht "action".
"action()" führt die Funktion aus und das Ergebnis ist, was die Funktion zurück gibt. (in deinem Fall "None", weil du nichts explizit zurück gibst).
"action" ist die Funktion.

Ketzt kannst du dir überlegen, was an den Button gebunden werden soll: Der Rückgabewert der ausgeführten Funktion - oder die Funktion.
perfekt, so funktionierts. Danke :D
Adn110
User
Beiträge: 3
Registriert: Sonntag 13. März 2022, 23:41

Sirius3 hat geschrieben: Montag 14. März 2022, 11:04 Benutze keine kryptischen Abkürzungen. Warum hängt an `datumd` ein d? Was soll bei kastenw das w? Warum eine Überschriftf?
Variablennamen müssen sprechend sein, und nicht zum Rätseln einladen.
r und l sind noch schlimmer, wobei es keinen schlimmeren Variablennamen als l gibt, weil man den leicht mit 1 oder I verwechseln kann.
Benutze keine globalen Variablen. Alles was eine Funktion braucht, muß sie über ihre Argumente bekommen. Bei `aktion` sind das text1 und text2.

In `NeueKarte` stückelst Du Strings per + zusammen. Statt dessen verwendet man Formatstrings. # als Trennzeichen ist ungewöhnlich. Datum formatiert man entweder Deutsch: dd.mm.yyyy oder in der Internationalen Variante yyyy-mm-dd (englisch würde man wohl eher nicht wählen, weil da nie klar ist, ob Monat oder Tag zuerst kommt).
Dateien öffnet man innerhalb eines with-Statements und der Filemode "a+" ist eigentlich nie sinnvoll; das muß "a" sein.

Es fehlt das Hauptprogramm (main), um zu verhindern, dass Du aus Versehen globale Variablen definierst.
`ueberschrift1`, `ueberschrifta` und `ueberschriftf` sind wenig sinnvolle Variablen, weil sie alle nur recht umständlich mit None initialisiert werden, dann aber nicht weiter benutzt werden.

`place` darf man bei GUIs nicht benutzen, weil sie je nach System zu unbenutzbaren Oberflächen führen.

Code: Alles auswählen

from datetime import date
import tkinter as tk
from functools import partial

def write_new_card(filename, question, answer):
    today = date.today()
    with open(filename, "a") as file:
        file.write(f"{question} # {answer} # {today:%Y-%m-%d}\n")


def aktion(text1, text2):
    print(text1.get())
    write_new_card("kasten.txt", text1.get(), text2.get())
    text1.delete(0,tk.END)
    text2.delete(0,tk.END)


def main():
    root = tk.Tk()
    tk.Label(root, text="Bitte gib deine Fragen ein", bg="orange").grid(row=0, column=0)
    tk.Label(root, text="Frage", bg="orange").grid(row=1, column=0)
    tk.Label(root, text="Antwort", bg="orange").grid(row=1, column=1)

    text1 = tk.Entry(root)
    text1.grid(row=2, column=0)
    text2 = tk.Entry(root)
    text2.grid(row=2, column=1)

    button1 = tk.Button(root, text="Ich bin fertig", command=root.destroy)
    button1.grid(row=3, column=0)
    button2 = tk.Button(root, text="Wort", command=partial(aktion, text1, text2))
    button2.grid(row=3, column=1)

    root.mainloop()

if __name__ == "__main__":
    main()
Haha, ja wenn ich nur so abends was ausprobiere, kopier ich Zeilen teilweise aus dem Internet (deswegen dreimal die "Überschrift") und halt mich auch nicht lange mit Variablen oder schönem Code auf. Aber du hast schonr echt, dass grad sowas wie die main funktion oder etwas aussagekräftigere Variablen wären nicht schlecht.

wegen dem Place aber noch eine Frage: Ich hab das auch schon gelesen, dass man das eher vermeiden soll, aber warum genau?
Also ich mach des ja grad eher als kleine Spielerei, des ist dann an meinen Bildschirm angepasst und insgesamt siehts halt schöner aus, als die mini textboxen find ich.
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Adn110: Place funktioniert halt nicht wirklich bei der heutigen Landschaft an Display-Grössen, -Auflösungen, und individuellen Einstellungen, zum Beispiel Schriftgrössen. Dann sieht das wenn man Glück hat einfach nur komisch aus, und wenn man Pech hat, wird die GUI unbenutzbar weil Texte nicht in den absoluten, dafür vorgegeben Platz passen, oder Anzeigeelemente teilweise oder ganz von anderen Anzeigeelementen überdeckt werden, so dass man wichtige Sachen nicht sieht, oder sogar gar nicht bedienen kann, wenn Eingabeelemente komplett verdeckt werden.

Es macht auch unnötig Arbeit an den Positionen und Grössen herum zu fummeln und auch deutlich mehr Arbeit, wenn man Elemente einfügen oder entfernen möchte, und dann alles was davon betroffen ist, manuell verschieben muss.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten