Повторная привязка «выбрать все» в текстовом виджете - PullRequest
9 голосов
/ 03 мая 2011

Я работаю с виджетом «Текст», и у меня возникла проблема с ярлыками старой школы, которые использует Tk.

Т.е.:

Выбрать все: Ctrl + / против Ctrl + a
Cut: Ctrl + w против Ctrl + x
Копия: Meta + w против Ctrl + c
Вставить: Ctrl + y против Ctrl + v

В Windows все они работают, кроме Ctrl + a.

1) Можно ли перенаправить привязки, поэтому .bind('<Control-a>') вызывает уже привязанные Ctrl + /?

2) Я пытался "выбрать все":

txt_text.bind('<Control-a>', self.ctext_selectall)

Где:

def ctext_selectall(self, callback):
    """Select all text in the text widget"""
    self.txt_text.tag_add('sel', '1.0', 'end')

Но это не работает, так как Ctrl + a работает по умолчанию (курсор перемещается в начало). Он работает с каким-то другим, несвязанным письмом. Есть ли какие-нибудь шансы сделать эту работу, если решение под 1 невозможно?

Ответы [ 2 ]

11 голосов
/ 03 мая 2011

Привязки по умолчанию применяются к классу виджетов.Когда вы делаете привязку, это влияет на определенный виджет, и эта привязка происходит до привязки класса.Таким образом, происходит то, что происходит ваше связывание, а затем происходит связывание классов, что создает впечатление, что ваше связывание не работает.

Есть два способа решить эту проблему.Во-первых, ваш ctext_selectall может вернуть строку "break", что предотвратит срабатывание привязки класса.Этого должно быть достаточно, чтобы решить вашу непосредственную проблему.

Второе решение заключается в изменении привязки класса, чтобы предпочтительная привязка применялась ко всем текстовым виджетам.Это можно сделать, используя метод bind_class.

Вот пример повторного связывания класса:

def __init__(...):
    self.root.bind_class("Text","<Control-a>", self.selectall)

def selectall(self, event):
    event.widget.tag_add("sel","1.0","end")

effbot.org имеет довольно приличную запись под названием Events and Bindings .В нем немного подробнее рассказывается о привязках классов и виджетов, а также о порядке их появления.

Механизм привязки Tk - это лучший из всех имеющихся инструментов GUI.Как только вы поймете, как это работает (и это удивительно просто), вы обнаружите, что легко дополнить или заменить любые или все привязки по умолчанию.

3 голосов
/ 03 мая 2011

Не стесняйтесь использовать следующий код или хотя бы проверить, как методы select_all реализованы в классах DiacriticalEntry и DiacriticalText. Если вы решите использовать классы в том виде, в каком они есть, вместо любого виджета, который вы используете в данный момент, вы также получите тот аванс, что пользователи смогут легко вводить определенные символы, которые в противном случае было бы труднее ввести.

## {{{ http://code.activestate.com/recipes/576950/ (r3)
from tkinter import *
from tkinter.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 as 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, **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, **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()
## end of http://code.activestate.com/recipes/576950/ }}}
...