Eingaben filtern bei Tkinter.Text() ?!?

Fragen zu Tkinter.
Antworten
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ich würde gern alle Eingaben vom Benutzer in einer Tkinter.Text() abfangen und evtl. ändern. Wie?

Ich könnte das machen (pseudocode):

Code: Alles auswählen

        self.text = Tkinter.Text(self.root, height=30, width=80)
        self.text.config(
            state=Tkinter.DISABLED # make textbox "read-only"
        )
        self.root.bind("<Key>", self.event_key_pressed)

    def event_key_pressed(self, event):
        char = event.char
        self.text.config(state=Tkinter.NORMAL)
        char = foobar(char)
        self.text.insert("end", char)
        self.text.see("end")
        self.text.config(state=Tkinter.DISABLED)
Das funktioniert theoretisch... Aber kann kann man nicht wirklich den Text editieren. Also z.B. mit den Cursortasten umherwandern usw.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
bfm
User
Beiträge: 88
Registriert: Donnerstag 14. März 2013, 09:42

Hallo,

da müsstest bei jedem Event den Keycode prüfen und wenn bestimmte Keycodes (Cursortasten) auftreten entsprechend reagieren.

hier mal aus meiner Sammlung einen Link. Der dürfte dir weiterhelfen:
http://docs.huihoo.com/tkinter/tkinter- ... names.html

mfg
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ja, das mit den Cursortasten ist dann das eigentliche Problem, wenn ich "<Key>" abfange. Aber kann ich nicht den Event abfangen, ändern und dann wieder "weiterleiten" ?

Ich nutzte nun "ScrolledText" um den es geht.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

Lesestoff: http://effbot.org/tkinterbook/tkinter-e ... ndings.htm

`event_generate()` und 'break' als Rückgabewert sollten hier interessant sein.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Also so geht es fast, aber nicht ganz (pseudocode):

Code: Alles auswählen

        self.text = Tkinter.Text(self.root, height=30, width=80)
        self.root.bind("<Key>", self.event_key_pressed)

    def event_key_pressed(self, event):
        keycode = event.keycode
        char = event.char
        log.critical("keycode %s - char %s", keycode, repr(char))
        if not char or char not in string.letters:
            log.critical("ignore")
            return

        converted_char = invert_shift(char)
        log.critical("Convet char %r to %r", char, converted_char)
        self.text.insert(Tkinter.CURRENT, converted_char)
        return "break"
1. Die Zeichen werden nun doppelt eingegeben: Ich dachte "break" würde das bewirken.
2. Neue Zeichen landen nicht an der richtigen Stelle: Ich dachte Tkinter.CURRENT ist die aktuelle Cursor Position??!

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Also ich werde da nicht so ganz schlau draus...

Es gibt ja nicht nur "<Key>" sondern auch "<KeyPress>" und "<KeyRelease>"...
Hab mal alle drei per bind() genutzt und jeweils ein "break" zurück "gesendet".

Wenn man "<KeyPress>" oder "<KeyRelease>" nutzt, dann wird anscheinend "<Key>" wirkungslos. (Liegt vielleicht am return "break" ?!?)

Aber egal welches ich nutzte, das Zeichen landet zuerst schon im Text() bzw. ScrolledText() und erst danach, kommen die bind() Methoden zum Zuge. Also zu spät?

Also wie geht es?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Schorlem
User
Beiträge: 40
Registriert: Dienstag 3. Juni 2014, 16:37

Hm, ich persönlich würde es nicht als beste Möglichkeit ansehen, alle Aktionen nochmal zu emulieren, was natürlich auch drauf ankommt, welche Features letztendlich implementiert werden sollen (Markieren, Cursor setzen, mit Tastatur markieren, ausschneiden, kopieren, einfügen, etc.). Was mich gerade noch quält ist, dass das Entry-Widget die perfekte Methode dafür bieten würde: Validation (mehr dazu hier). Man könnte sich dann reichlich unelegant etwas daraus zusammenbasteln, allerdings ist direkt das nächste Problem da: Wie sollen Eingaben über mehrere Zeilen gelöst werden? Und was ist, wenn eine vorherige Zeile bearbeitet werden soll?
Leider und warum auch immer bietet 'Text' bzw. 'ScrolledText' keine dieser Validierungsfunktionen.

Außer dem wirklichen Emulieren der ganzen Tasten(kombinationen) erscheint mir momentan keine der genannten Lösungen greifbar :/
Naja, vielleicht hat noch jemand 'ne Idee^^
Diese Nachricht wurde maschinell erstellt und ist daher ohne Unterschrift gültig.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Danke für die Hinweise...

Eigentlich möchte ich nur Groß-/Kleinschreibung ändern, damit:

Code: Alles auswählen

def invert_shift(chars):
    """
    >>> invert_shift("a")
    'A'
    >>> invert_shift("A")
    'a'

    >>> invert_shift("123 foo 456 BAR #!")
    '123 FOO 456 bar #!'
    """
    result = ""
    for char in chars:
        if char in string.ascii_lowercase:
#             log.critical("auto shift lowercase char %s to UPPERCASE", repr(char))
            char = char.upper()
        elif char in string.ascii_uppercase:
#             log.critical("auto shift UPPERCASE char %s to lowercase", repr(char))
            char = char.lower()
        result += char
    return result

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hab nun eine Lösung: https://gist.github.com/jedie/ae4f974d00a417183b2c

Das wichtigste:

Code: Alles auswählen

...

    self.root.bind("<Key>", self.event_key)

    ...

    converted_char = char.upper()
    self.text.delete("insert-1c") # Delete last input char
    self.text.insert(Tkinter.INSERT, converted_char) # Insert converted char
    return "break" 

Und im Einsatz: https://github.com/jedie/DragonPy/commi ... ee2f0095be

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Noch eine saubere Lösung gefunden: https://gist.github.com/jedie/ae4f974d0 ... /revisions

Das Problem war, das ich self.root.bind("<Key>"... gemacht habe und in dem Fall passender ist: self.text.bind("<Key>"...

Dann bewirkt auch das return "break" das kein Zeichen ankommt. Also muß ich auch nicht umständlich die alte Eingabe löschen.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten