@_Scaui: Die `pop()`-Methode kennt ein Default-Argument, damit kann man sich in der `__init__()` das ``if``/``else`` sparen.
In der `__init__()` einfach so `master.register()` aufrufen geht nicht, denn der Default-Wert davon ist ja `None` und `None` hat keine `register()`-Methode. Da die auf *jedem* Widget existiert, kann man da einfach `self` verwenden.
Das ``if``/``else`` in `Entry.validate()` ist auch überflüssig, denn die Bedingung ergibt einen Wahrheitswert, dessen Gegenteil als Ergebnis zurückgegeben wird. Da kann man einfach die Bedingung umkehren und deren Ergebnis direkt zurückgeben.
Dein `Entry.validate()` verdeckt die originale `ttk.Entry.validate()`-Methode, die dadurch nicht mehr benutzbar ist. Dein `Entry.validate()` sollte vielleicht auch gar nicht zur öffentlichen API gehören.
Deine `configure()`-Methode hat eine andere Signatur und eine leicht andere Semantik als die originale `configure()`-Methode. Und das obwohl Du das sogar beim Aufruf der originalen Methode nutzt, nämlich das man beispielsweise auch ein Wörterbuch mit Optionen als erstes Argument übergeben kann, statt das über Schlüsselwort-Argumente zu machen.
Und da `configure()` auch einzelne Optionen *abfragen* kann, muss man das Ergebnis des originalen Aufrufs auch mit ``return`` zurück geben.
Wenn man das korrigiert, gehen auch lesende und schreibende ``widget["option"]``-Zugriffe wieder.
`i` ist ein ganz schlechter Name für Zeichen und dazu noch in einer Schleife wo `i` eigentlich immer für eine ganze Zahl steht.
Bei `copy_in()`, was vielleicht auch nicht zur öffentlichen API gehören sollte, heisst das nicht verwendete Ereignisobjekt `text`, was ziemlich irreführend ist.
Man sollte nicht implizit `None` zurück geben (lassen). Wenn man ``return`` verwendet, sollte jeder Weg durch die Funktion/Methode auch ein ``return`` mit einem expliziten Rückgabewert haben.
Die originale `tk.Text.insert()`-Methode erlaubt die zusätzliche Angabe eines Tags und noch weitere Zeichen und Tags als Argumente. Mindestens das erste Tag sollte man noch durchreichen, damit das in der Funktionalität nicht zu sehr gegenüber dem Original eingeschränkt wird.
Und dann gibt es mindestens noch `tk.Text.replace()` mit dem man dann doch noch `gesperrte_tasten` umgehen kann.
Zwischenstand (ungetestet):
Code: Alles auswählen
#!/usr/bin/env python3
import tkinter as tk
from tkinter import ttk
class Entry(ttk.Entry):
def __init__(self, master=None, **kwargs):
self.gesperrte_tasten = kwargs.pop("gesperrte_tasten", [])
super().__init__(master, **kwargs)
self.config(
validate="key",
validatecommand=(self.register(self._validate), "%S"),
)
self.bind("<Control-v>", self._paste)
def _validate(self, value):
return value not in self.gesperrte_tasten
def configure(self, cnf=None, **options):
if "gesperrte_tasten" in options:
self.gesperrte_tasten = options.pop("gesperrte_tasten")
return super().configure(cnf, **options)
config = configure
def insert(self, index, string):
for character in string:
if character not in self.gesperrte_tasten:
super().insert(index, character)
def _paste(self, _event):
self.insert("insert", self.clipboard_get())
return "break"
#
# TODO Look what other methods need to be overridden. At least `replace()`.
#
class Text(tk.Text):
def __init__(self, master=None, **kwargs):
self.gesperrte_tasten = kwargs.pop("gesperrte_tasten", [])
super().__init__(master, **kwargs)
self.bind("<Any-KeyPress>", self._validate)
self.bind("<Control-v>", self._paste)
def _validate(self, event):
return "break" if event.char in self.gesperrte_tasten else None
def configure(self, cnf=None, **options):
if "gesperrte_tasten" in options:
self.gesperrte_tasten = options.pop("gesperrte_tasten")
return super().configure(cnf, **options)
config = configure
def insert(self, index, chars):
#
# TODO Orginal method allows giving a tag, and additional chars and tags
# as arguments.
#
for character in chars:
if character not in self.gesperrte_tasten:
super().insert(index, character)
def _paste(self, _event):
self.insert("insert", self.clipboard_get())
return "break"
def main():
fenster = tk.Tk()
fenster.title("Texttest")
ttk.Label(fenster, text="Du kannst keine As, Bs und Cs eingeben!").pack()
entry = Entry(fenster, gesperrte_tasten="abcABC")
entry.focus_set()
entry.pack()
ttk.Label(fenster, text="Und hier auch nicht!").pack()
text = Text(fenster, gesperrte_tasten="abcABC")
text.pack()
fenster.mainloop()
if __name__ == "__main__":
main()