在Text控件中重新绑定“全选”操作

11

我正在使用Text小部件,关于Tk使用的老式快捷键有一个问题。

例如:

全选:Ctrl + / vs Ctrl + a
剪切:Ctrl + w vs Ctrl + x
复制:Meta + w vs Ctrl + c
粘贴:Ctrl + y vs 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默认情况下起作用(光标移到开头)。它可以与其他一些未绑定的字母一起使用。如果第一种解决方案不可行,有没有使它起作用的机会?

2个回答

15

默认的绑定应用于小部件类。当你进行绑定时,它会影响到特定的小部件,并且该绑定会在类绑定之前发生。所以正在发生的是你的绑定先执行,然后是类绑定,这使得你的绑定似乎不起作用。

有两种方法可以解决这个问题。其一,你的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有一篇相当不错的文章,标题为"事件和绑定"。它对类和部件的绑定以及它们发生的顺序进行了更详细的介绍。

Tk的绑定机制是所有GUI工具包中最好的。一旦你理解了它的工作原理(它非常简单),你会发现很容易增强或替换任何默认绑定。


4

请随意使用以下代码,或至少查看DiacriticalEntryDiacriticalText类中实现select_all方法的方式。 如果您选择使用这些类来替换当前使用的任何小部件,则还将获得用户可以轻松输入某些本来更难输入的字符的优势。

## {{{ 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/ }}}

正如所指出的那样,此代码解决的问题不仅包括选择所有文本,还可以轻松输入带有变音符号的字符。这些类可原样用于增强Tkinter,或者marw可以引用“select_all”方法来编写自己的代码。 - Noctis Skytower
谢谢,我怀疑以后有一天我会回来看这个 :) - marw
感谢您提醒我 "<Control-Key-x><Key>"。 :D - Honest Abe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接