Wie fixt man: "_tkinter.TclError: bad state "readonly""?

Fragen zu Tkinter.
Antworten
anditp6
User
Beiträge: 3
Registriert: Sonntag 13. Juni 2021, 00:07

Hallo,

bin komplett Python-Newbie. Hatte war viel mit Java gemacht. Aber bei Python bin ich total lost. Ich schreibe gerade an mein allererstes Projekt. Soll ein Unit Converter sein. Ich bekomme folgende Fehler: "_tkinter.TclError: bad state "readonly": must be active, disabled, or normal". Konnte fast nix dazu auf google finden. Kann jemand mit bitte helfen bzw erklaeren, was schief lief?

Code: Alles auswählen

import tkinter as tk
from tkinter import *
from tkinter import ttk

import Calculation

class UnitConvertion(tk.Tk):
    def __init__(self):
        super().__init__()
        self.caldict = Calculation.calculation_dictionaries
        # window configuration
        self.geometry("550x250")
        self.title("Unit Converter")
        self.configure(bg="light grey")
        self.resizable(height=False, width=False)

        # labels
        self.scales_lbl = Label(self, text="Choose scales", bg="black", fg="white", width=15)
        self.scales_lbl.grid(column=0, row=0, sticky=W, padx=4, pady=4)
        self.input_value_lbl = Label(self, text="Input value", bg="black", fg="white", width=15)
        self.input_value_lbl.grid(column=0, row=1, sticky=W, padx=4, pady=4)
        self.convert_from_lbl = Label(self, text="Convert from", bg="black", fg="white", width=15)
        self.convert_from_lbl.grid(column=0, row=2, sticky=W, padx=4, pady=4)
        self.convert_to_lbl = Label(self, text="Convert to", bg="black", fg="white", width=15)
        self.convert_to_lbl.grid(column=2, row=2, sticky=W, padx=4, pady=4)

        self.result = StringVar()
        self.result_lbl = Label(self, textvariable=self.result, state="readonly")

        # Entry
        self.unit_value = DoubleVar()
        self.unit_entry = Entry(self, textvariable=self.unit_value, width=23)
        self.unit_entry.grid(column=1, row=1, sticky=W, padx=4, pady=4)

        # comboboxes
        self.scale_string = StringVar()
        self.scales_options_cbx = ttk.Combobox(self, textvariable=self.scale_string_cbx, state="readonly",
                                               values=tuple([available_scales.upper() for available_scales in self.caldict.keys()]))
        self.scales_options_cbx.bind("<<SelectedCombobox>>", self.setUnits)
        self.scales_options_cbx.grid(column=1, row=0, sticky=E, padx=4, pady=4)
        self.unit_value_from = StringVar()
        self.from_options_cbx = ttk.Combobox(self, textvariable=self.unit_value_from, state="readonly")
        self.from_options_cbx.grid(column=1, row=2, sticky=E, padx=4, pady=4)
        self.unit_value_to = StringVar()
        self.to_options_cbx = ttk.Combobox(self, textvariable=self.unit_value_to, state="readonly")
        self.to_options_cbx.grid(column=4, row=2, sticky=E, padx=4, pady=4)

        # Buttons
        self.convert_btn = Button(self, text="Calculate", width=15, command=self.calculation())
        self.convert_btn.grid(row=3, padx=4, pady=4)

    def setUnits(self):
        self.unit_from["value"] = tuple(self.caldict.get().upper().keys())
        self.unit_to["value"] = tuple(self.caldict.get().upper().keys())

    def calculation(self):
    	# TODO
        pass

if __name__ == "__main__":
    application = UnitConvertion()
    application.mainloop()
Hier ist ein Ausschnitt der Einheiten Dictionary

Code: Alles auswählen

calculation_dictionaries = {
    "time": {
       "hours": {
           "seconds": lambda x: x * 60 * 60,
           "minutes": lambda x: x * 60,
           "hours": lambda x: x,
       },
       "minutes": {
           "seconds": lambda x: x * 60,
           "minutes": lambda x: x,
           "hours": lambda x: x / 60,
       },
       "seconds": {
           "seconds": lambda x: x,
           "minutes": lambda x: x / 60,
           "hours": lambda x: x / (60 * 60),
       }
    },
    ...
    }
    if __name__ == "__main__":
    try:
        # format for decimal points
        print("{0:.6f}".format(
            calculation_dictionaries["length"]["millimeters"]["centimeters"]["decimeters"]["meters"](4)))
    except TypeError:
        pass
    except KeyError:
        pass
    for cd in calculation_dictionaries.keys():
        print(cd.capitalize())
        print(tuple(calculation_dictionaries[cd].keys()))
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Jetzt wäre noch der komplette Traceback nett, dass wir nicht raten müssen, wo der Fehler ist.
Im Modul Calculation hast Du einen Einrückfehler. Module werden wie Methoden und Variablen komplett klein geschrieben. *-Importe benutzt man nicht. Nicht alles muß man an Attribute binden, z.B Labels, auf die man nie wieder zugreift.
Statt von jeder zu jeder Einheit einen eigenen Konverter zu schreiben würde man nur einen von und zu einer Basiseinheit schreiben. Das spart N^2‐2N Funktionen. Bei einfachen linearen Abbildungen reicht auch die Angabe von ein bis zwei Zahlen.
anditp6
User
Beiträge: 3
Registriert: Sonntag 13. Juni 2021, 00:07

Sirius3 hat geschrieben: Sonntag 13. Juni 2021, 17:34 Jetzt wäre noch der komplette Traceback nett, dass wir nicht raten müssen, wo der Fehler ist.
Oh sry, habe vergessen, den Traceback zu posten.
Sirius3 hat geschrieben: Sonntag 13. Juni 2021, 17:34 Im Modul Calculation hast Du einen Einrückfehler.

meinst du den schliessende Klammer vom dictionary?

Code: Alles auswählen

Traceback (most recent call last):
  File "E:/Code Practices/Python/BeginnerLevelApplications/ScaleConverter/Converter.py", line 60, in <module>
    application = UnitConvertion()
  File "E:/Code Practices/Python/BeginnerLevelApplications/ScaleConverter/Converter.py", line 28, in __init__
    self.result_lbl = Label(self, text=self.result, state="readonly")
  File "C:\Users\xiaom\anaconda3\envs\ScaleConverter\lib\tkinter\__init__.py", line 3148, in __init__
    Widget.__init__(self, master, 'label', cnf, kw)
  File "C:\Users\xiaom\anaconda3\envs\ScaleConverter\lib\tkinter\__init__.py", line 2572, in __init__
    self.tk.call(
_tkinter.TclError: bad state "readonly": must be active, disabled, or normal
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Der Fehler sagt es doch klar. readonly gibt es nicht. Must be active, disabled, or normal.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Die Fehlermeldung sagt es ja schon deutlich. `state` kann nur die werte active, disabled oder normal annehmen. Was soll bei einem Label `readonly` eigentlich bedeuten?
Das result-Label wird gar nicht platziert. Button erwartet als command eine Funktion, nicht den Rückgabewert des Funktionsaufrufs.
`scale_string_cbx` wird nirgends definiert. Absolute Größenangaben sind schlecht, vor allem, wenn man das Fenster nicht-größenveränderbar macht. Bei mir ist das Fenster damit unbedienbar.
`setUnits` wird nirgends benutzt. `get` bei einem Wörterbuch braucht ein Argument. Wörterbücher haben keine upper-Methode.
`unit_from` und `unit_to` existieren nicht.
anditp6
User
Beiträge: 3
Registriert: Sonntag 13. Juni 2021, 00:07

Sirius3 hat geschrieben: Sonntag 13. Juni 2021, 18:31 Die Fehlermeldung sagt es ja schon deutlich. `state` kann nur die werte active, disabled oder normal annehmen. Was soll bei einem Label `readonly` eigentlich bedeuten?
Oh hab da wohl schlicht weg nicht gecheckt, dass die Loesung bereits vorm Auge ist. Bei readonly habe ich da wohl bissl was noch von C# reingemixt. readonly ist dort das keyword, dass der variable nicht mehr im nachhinein veraendert bzw. ueberschrieben werden kann. Komischerweise habe ich "readonly" bei diversen tutorial Seiten gefunden. :?
Sirius3 hat geschrieben: Sonntag 13. Juni 2021, 18:31 Absolute Größenangaben sind schlecht, vor allem, wenn man das Fenster nicht-größenveränderbar macht. Bei mir ist das Fenster damit unbedienbar.
oh ok. Wollte das Fenster urspruenglich dynamic machen. Also responsive wie bei Webentwicklung. Wollte das hier machen. Hat aber bei mir gar nicht funktioniert.

Code: Alles auswählen

self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das alleine ist nicht ausreichend um zu beurteilen, was da passiert ist. Du musst dann auch den grid manager benutzen. Wobei man den jetzt gar nicht unbedingt braucht, auch horizontales und vertikales Stacking ist adaptiv.
Antworten