Automatisch Entrys erzeugen - Fehler abfangen

Fragen zu Tkinter.
Antworten
Sabbse92
User
Beiträge: 13
Registriert: Samstag 29. Februar 2020, 20:02

Hallo,

im folgenden Code, kann der Benutzer eine Zahl N eingeben. Das Programm erzeugt dann automatisch (mithilfe von tkinter Variablen und Trace) N Zeilen.

Code: Alles auswählen

from tkinter import *

root = Tk()
Label(root, text = "Enter Number of columns").grid(row = 0, column = 0)
N = IntVar()
e_N = Entry(root, textvariable = N).grid(row = 0, column = 1)

# Put trace callbacks on the Entry IntVar
def create_rows(name, index, mode):
    rows = N.get()
    for i in range(rows):
        Entry(root).grid(row = i + 1, column = 0)

N.trace('w', create_rows)
# Setting the vars will trigger the trace
N.set(2)

mainloop()
Wenn man die eingegebene Zahl löscht um eine neue Zahl einzugeben, taucht eine Fehlermeldung auf:

Code: Alles auswählen

Exception in Tkinter callback
Traceback (most recent call last):
  File "/home/erich/anaconda3/lib/python3.7/tkinter/__init__.py", line 508, in get
    return self._tk.getint(value)
_tkinter.TclError: expected integer but got ""

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/erich/anaconda3/lib/python3.7/tkinter/__init__.py", line 1705, in __call__
    return self.func(*args)
  File "<ipython-input-120-42d7236d23c8>", line 10, in create_rows
    rows = N.get()
  File "/home/erich/anaconda3/lib/python3.7/tkinter/__init__.py", line 510, in get
    return int(self._tk.getdouble(value))
_tkinter.TclError: expected floating-point number but got ""
Der Grund für diese Fehlermeldung ist wahrscheinlich:
Der Wert von N wird verfolgt, d.h., dass bei jeder Änderung create_rows aufgerufen wird. Auch kurz nachdem die ursprüngliche Nummer gelöscht wird, aber bevor eine neue Nummer eingeben wird.

Ich möchte diesen Fehler abfangen, indem ich N.get() in einen try/except Block schreibe.

Leider weiß ich jedoch nicht, wie das umsetzen soll. Ich habe versucht N.get() durch

Code: Alles auswählen

    try:
        rows = N.get()
    except _tkinter.TclError: 
         " "
zu ersetzen, was leider nicht geklappt hat. Hat jemand von euch eine Idee, wie man das Problem lösen kann.
Sirius3
User
Beiträge: 18289
Registriert: Sonntag 21. Oktober 2012, 17:20

*-Importe sind böse. Auf oberster Ebene sollte nichts außer (Funktions-)Definitionen und Konstanten stehen, der ganze Rest sollte in eine Funktion wandern, die üblicherweise main genannt wird. N und e_N sind äußerst schlechte Variblennamen, weil sie sich zum einen nicht an die Namenskonvention, alle Variablen werden klein_mit_unterstrich geschrieben, halten, sondern weil sie zudem nichtssagende einbuchstabige Abkürzungen sind. Variablennamen müssen aussagekräftig sein.
e_N wird zudem an None gebunden und zum Glück auch nicht weiter verwendet.
alles, was eine Funktion braucht, sollte sie über ihre Argumente bekommen, create_rows braucht zumindest root und die Eingabe.
`TclError` ist im selben Namensraum wie die anderen Tk-Namen.

Code: Alles auswählen

from functools import partial
import tkinter as tk

def create_rows(name, index, mode, root=None, eingabe=None):
    try:
        rows = eingabe.get()
    except tk.TclError:
        pass
    else:
        for i in range(rows):
            tk.Entry(root).grid(row=i+1, column=0)

def main():
    root = tk.Tk()
    tk.Label(root, text="Enter Number of columns").grid(row=0, column=0)
    eingabe = tk.IntVar(root, 2)
    eingabe.trace('w', partial(create_rows, root=root, eingabe=eingabe))
    tk.Entry(root, textvariable=eingabe).grid(row=0, column=1)
    root.mainloop()

if __name__ == '__main__':
    main()
Der Code erzeugt jetzt munter übereinander liegende Eingabefelder, an die man nicht mehr rankommt.
Jedes nicht-triviale GUI-Programm braucht aber eigentlich Klassen-Definitionen, um sich Zustand sauber merken zu können.
Sabbse92
User
Beiträge: 13
Registriert: Samstag 29. Februar 2020, 20:02

Vielen Dank Sirius3.

Jetzt habe ich eine klare Vorlage, an welcher ich den restliche Code orientieren kann. Warum werden zu Beginn nicht direkt 2 Entry angezeigt?
Die Variable eingabe = tk.IntVar(root, 2) hat doch den Wert 2?


Ich hätte noch eine Frage zum obigen Beispiel:
Angenommen man erzeugt zuerst 5 Entrys. Danach tippt man 3 ein! Als Resultat werden immernoch 5 Entry angezeigt, anstatt 3. Ist es möglich die letzten 5-3 Entry automatisch zu löschen?
Sirius3
User
Beiträge: 18289
Registriert: Sonntag 21. Oktober 2012, 17:20

Wie ich schon geschrieben hatte, werden ständig neue Entry-Felder erzeugt. Von den 5 + 3 = 8 Entryfeldern sind halt 3 durch die neuen verdeckt.
Du mußt Dir eh alle Entry-Felder in einer Liste merken, dann kannst Du Dir auch gleich die Differenz berechnen und nur die Felder entfernen oder hinzufügen, die nötig sind.
Sabbse92
User
Beiträge: 13
Registriert: Samstag 29. Februar 2020, 20:02

Okay, vielen Dank!
Antworten