Применить теги в текстовом виджете - PullRequest
0 голосов
/ 05 октября 2011

Мне нужна помощь, связанная с тегами!

Я пишу простой редактор, поддерживающий базовое форматирование. С помощью виджета «Текст» (с именем text ) я поместил тег «b», чтобы установить текст, к которому этот тег относится к жирному шрифту.

Это не проблема, когда я применяю жирный шрифт к выделению:

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

Вместо этого у меня две проблемы, когда я просто хочу включить / выключить жирный шрифт при наборе текста. Чтобы переключить его на единственный способ, который я нашел, это:

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

обратите внимание, что мне нужно вставить ДВА пробела. Если я вставлю один, жирный шрифт не применяется. Если я вставлю '', мой курсор вернется на один символ!

Моя вторая проблема заключается в том, как отключить его, когда я пишу в выделенной области - и для этого у меня нет ни малейшей идеи ...

Спасибо за любую помощь!

Ответы [ 2 ]

3 голосов
/ 05 октября 2011

Вы можете не осознавать этого, но вы пытаетесь сделать что-то очень сложное в Tkinter.Хотя текстовые теги виджетов являются мощной концепцией, у них есть некоторые недостатки, когда речь идет о создании чего-то вроде редактора wysywig.

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

Когда вы вставляете символ в текстовый виджет, это обрабатывается привязкой к событию <Key> в классе текстового виджета.Таким образом, мы можем привязать к <Key>, чтобы добавить тег.Однако, если мы добавим привязку к <Key> в виджете, это вызовет перед привязкой класса, что означает, что наш код будет выполняться до вставленного символа, а не после.Мы будем пытаться изменить что-то, что еще не было вставлено в виджет.

Один из способов решить эту проблему - привязать к клавише release вместо нажатия клавиши,так как символ вставлен в печать.Однако подумайте о сценарии, в котором пользователь нажимает и удерживает клавишу - будет введено несколько символов, но вы можете получить только одно событие нажатия клавиши.Так что это решение не особенно хорошо.

Другое решение состоит в том, чтобы каким-то образом организовать нашу пользовательскую привязку, которая произойдет после привязки по умолчанию.Для этого нам нужно сделать две вещи: 1) настроить «теги привязки», чтобы виджет имел дополнительный тег после тега класса, и 2) добавить привязку к этому новому тегу привязки.

Тамнедостатки этого подхода тоже.Не из-за тегов связывания, а потому, что нужно обрабатывать гораздо больше событий, кроме <Key> (например, control-v для вставки не обрабатывается привязкой <Key>, поэтому вам придется добавитьособый случай для вставки).

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

В следующем примере у меня есть текстовый виджет с дополнительным тегом привязки с именем «CustomText», который мы помещаем после стандартного тега привязки «Текст».Я добавил привязку к этому тегу для события <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()
0 голосов
/ 14 октября 2011

Спасибо, Брайан, но ваш подход кажется мне слишком сложным, и я не очень хочу писать привязки к тому, чего не хватает - 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')

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

1010 * Alessandro *

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...