This module provides two standard Tkinter widgets, Entry and ScrolledText, modified for text editing with key bindings that allow entering accented letters, umlauts, etc.
Usage: To enter an accented character, press Ctrl-symbol, then press the character key. Example: to enter U with umlaut, press Ctrl-", U. For accent symbols that need shift, press Ctrl-Shift-symbol (for example, Ctrl-Shift-' if " is under Shift-').
Accent bindings are defined in the Diacritical.accent table. Not all accents exist on all letters. This is handled by gracefully falling back to the base letter.
Additional changes in default Tk key bindings: Ctrl-A is now select-all.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | from Tkinter import *
from ScrolledText import ScrolledText
from unicodedata import lookup
import os
class Diacritical:
"""Mix-in class that adds keyboard bindings for accented characters, plus
other common functionality.
An inheriting class must define a select_all method that will respond
to Ctrl-A."""
accents = (('acute', "'"), ('grave', '`'), ('circumflex', '^'),
('tilde', '='), ('diaeresis', '"'), ('cedilla', ','),
('stroke', '/'), ('ring above', ';'))
def __init__(self):
# Fix some key bindings
self.bind("<Control-Key-a>", self.select_all)
# We will need Ctrl-/ for the "stroke", but it cannot be unbound, so
# let's prevent it from being passed to the standard handler
self.bind("<Control-Key-/>", lambda event: "break")
# Diacritical bindings
for a, k in self.accents:
# Little-known feature of Tk, it allows to bind an event to
# multiple keystrokes
self.bind("<Control-Key-%s><Key>" % k,
lambda event, a=a: self.insert_accented(event.char, a))
def insert_accented(self, c, accent):
if c.isalpha():
if c.isupper():
cap = 'capital'
else:
cap = 'small'
try:
c = lookup("latin %s letter %c with %s" % (cap, c, accent))
self.insert(INSERT, c)
# Prevent plain letter from being inserted too, tell Tk to
# stop handling this event
return "break"
except KeyError, e:
pass
class DiacriticalEntry(Entry, Diacritical):
"""Tkinter Entry widget with some extra key bindings for
entering typical Unicode characters - with umlauts, accents, etc."""
def __init__(self, master=None, **kwargs):
Entry.__init__(self, master=None, **kwargs)
Diacritical.__init__(self)
def select_all(self, event=None):
self.selection_range(0, END)
return "break"
class DiacriticalText(ScrolledText, Diacritical):
"""Tkinter ScrolledText widget with some extra key bindings for
entering typical Unicode characters - with umlauts, accents, etc."""
def __init__(self, master=None, **kwargs):
ScrolledText.__init__(self, master=None, **kwargs)
Diacritical.__init__(self)
def select_all(self, event=None):
self.tag_add(SEL, "1.0", "end-1c")
self.mark_set(INSERT, "1.0")
self.see(INSERT)
return "break"
def test():
frame = Frame()
frame.pack(fill=BOTH, expand=YES)
if os.name == "nt":
# Set default font for all widgets; use Windows typical default
frame.option_add("*font", "Tahoma 8")
# The editors
entry = DiacriticalEntry(frame)
entry.pack(fill=BOTH, expand=YES)
text = DiacriticalText(frame, width=76, height=25, wrap=WORD)
if os.name == "nt":
# But this looks better than the default set above
text.config(font="Arial 10")
text.pack(fill=BOTH, expand=YES)
text.focus()
frame.master.title("Diacritical Editor")
frame.mainloop()
if __name__ == "__main__":
test()
|
This recipe shows a couple of less-known tricks in Tk: binding an event to a multiple keystroke sequence and setting a default option (font, in this case) for all widgets inside a frame.
Also note that the Shift key works "transparently" here - for Ctrl-" (umlaut) you usually have to press Ctrl-Shift-' and it works as expected.
Known issues: For this recipe to work you need Unicode support in Python and in Tk.
Changed in this version: comment improvements, minor cleanup.
About the tilde. ('tilde', '='),I believe that one would be the correct--> ('tilde', '~')
Couldn't get it to work. That was initially the idea, but I couldn't get it to work. Since I couldn't use Ctrl-c for cedilla anyway (which would follow the pattern for TeX-like accents), I just gave up on the tilde.