在文本小部件中应用标签

时间:2011-10-05 09:16:11

标签: python tkinter

我需要一些与标签相关的帮助!

我正在编写一个简单的编辑器,支持基本格式。 通过使用文本小部件(名为 text ),我将标记'b'设置为此标记应用于粗体的文本。

将粗体应用于选区时,这不是问题:

text.tag_add('b', SEL_FIRST,SEL_LAST)

当我只想在打字时打开/关闭粗体时,我遇到了两个问题。 要以我发现的唯一方式切换它是:

text.insert(INSERT, '  ', 'b' )
text.mark_set("insert", INSERT+'-1c')

请注意我必须插入两个空格。如果我插入一个,粗体不适用。如果我插入'',我的光标会返回一个字符!

我的第二个问题是当我在一个粗体区域内写作时如何关闭它 - 为此我没有丝毫想法......

感谢您的帮助!

2 个答案:

答案 0 :(得分:3)

你可能没有意识到这一点,但你正试图在Tkinter做一些非常难的事情。虽然文本小部件标签是一个强大的概念,但它们在创建像wysywig编辑器这样的东西时有一些缺点。

你需要改变一下你的方法。我认为更好的解决方案是添加在每次插入字符时应用(或删除)标记的绑定,而不是插入空格。这有它自己的一系列问题,但是如果对细节有足够的重视,你就可以克服它们。我们可以通过自定义键绑定来实现。

当您将字符插入文本小部件时,这是通过对文本小部件类的<Key>事件的绑定来处理的。因此,我们可以绑定到<Key>来添加标记。但是,如果我们在窗口小部件上向<Key>添加绑定,则会在类绑定之前触发,这意味着我们的代码将在插入字符之前而不是之后执行。我们将尝试修改尚未实际嵌入到小部件中的内容。

解决这个问题的一种方法是绑定到键发布而不是按键,因为该字符已插入印刷机。但是,请考虑用户按下并按住按键的情况 - 将输入多个字符,但您可能只获得一个按键事件。所以这个解决方案并不是特别好。

另一个解决方案是以某种方式安排我们的自定义绑定在默认绑定后发生。为此,我们需要做两件事:1)调整窗口小部件的“绑定标记”,使其在类标记之后有一个额外的标记,以及2)为这个新的绑定标记添加一个绑定。

这种方法也存在缺点。不是因为绑定标记,而是因为除了<Key>之外还需要处理更多事件(例如,对于<Key>绑定不会处理control-v to paste,所以你'我必须添加一个特殊的粘贴案例。)

话虽这么说,这个解决方案可能对您来说足够好,或者至少足以帮助您更好地理解问题,而理解问题通常是找到解决方案的最大障碍。

在下面的示例中,我有一个文本小部件,其中包含一个名为“CustomText”的附加标签,我们将其放在标准的“Text”绑定标记之后。我为<Key>事件在此标记上设置了绑定,在处理程序中,我只是将适当的标记应用于刚插入的字符。

您必须添加自己的代码来处理剪贴板粘贴,以及处理冲突标记的问题(例如两个标记,每个标记都有自己的字体)。但是,希望这个例子能充当灵感

import Tkinter as tk

class SampleApp(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        self.tag_vars = {
            "underline": tk.IntVar(),
            "red": tk.IntVar(),
            }

        self.text = MyText(self, width=40, height=8)
        self.text.tag_configure("red", foreground="red")
        self.text.tag_configure("underline", underline=True)

        toolbar = tk.Frame(self)
        self.underline = tk.Checkbutton(self, text="Underline", 
                                        onvalue = True, offvalue=False,
                                        variable = self.tag_vars["underline"]
                                        )
        self.red = tk.Checkbutton(self, text="Red", 
                                  onvalue = True, offvalue=False,
                                  variable = self.tag_vars["red"]
                                  )
        self.underline.pack(in_=toolbar, side="left")
        self.red.pack(in_=toolbar, side="left")

        toolbar.pack(side="top", fill="x")
        self.text.pack(side="top", fill="both", expand=True)

class MyText(tk.Text):
    def __init__(self, parent, *args, **kwargs):
        tk.Text.__init__(self, *args, **kwargs)

        self.parent = parent

        # add a new bind tag, "CustomText" so we
        # can have code run after the class binding
        # has done it's work
        bindtags = list(self.bindtags())
        i = bindtags.index("Text")
        bindtags.insert(i+1, "CustomText")
        self.bindtags(tuple(bindtags))

        # set a binding that will fire whenever a 
        # self-inserting key is pressed
        self.bind_class("CustomText", "<Key>", self.OnKey)

    def OnKey(self, event):
        # we are assuming this is called whenever 
        # a character is inserted. Apply or remove
        # each tag depending on the state of the checkbutton
        for tag in self.parent.tag_vars.keys():
            use_tag = self.parent.tag_vars[tag].get()
            if use_tag:
                self.tag_add(tag, "insert-1c", "insert")
            else:
                self.tag_remove(tag, "insert-1c", "insert")

if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()

答案 1 :(得分:-1)

谢谢Bryan,但是你的方法在我看来太复杂了,我并不急于开始为缺少的东西编写绑定 - paste 作为一个例子!

我简单地写下了以下内容,似乎有效

        l=text.tag_names('insert')
        if l==() or l[0]!='b':   # select bold
          text.insert(INSERT, '  ', 'b' )
          text.mark_set('insert', 'insert-1c')
        else:                    # deselect bold
          text.insert(INSERT, ' ' )
          text.tag_remove ('b','insert-1c') 
          text.mark_set('insert', 'insert-1c')

我唯一剩下的问题是,我没有找到一种在选择粗体时不插入额外空间的方法 - 但我可以忍受它......

的Alessandro