簡體   English   中英

Tkinter:斜體化已加粗的文本(重疊標簽)

[英]Tkinter: italicizing already bold text (overlapping tags)

我有一個Python Tkinter程序,可以在其中選擇文本,按快捷鍵,它將使選定的文本變為粗體。 您可以對其他樣式使用不同的快捷方式,例如斜體。

但是,作為正在運行的程序中的用戶時,我遇到了一個問題,如果我嘗試通過快捷方式使已經粗體的文本變為斜體,則該文本只會顯得是斜體,而不是粗體和斜體。 我知道這是有道理的,因為將標簽分配給一個標簽或另一個標簽,並且同時執行這兩個操作不會合並標簽的效果。 但是,我不知道確定文本上有多個標簽時會發生什么的方法。

您能否有一個以某種方式表示其他兩個特定標簽重疊的標簽?

我看到要處理此問題的唯一方法(從我在文檔中看到的)是使用Text.tag_bind將一個函數綁定到我的每個樣式標簽,這些標簽會做一些有趣的事情來制作正確的文本,並且只有正確的文本,粗體和斜體。 我想這是可行的,但是如果這不是正確的方法,我想知道。

我可以輕松制作一次同時執行粗體和斜體的標簽。 我需要的是能夠處理重疊的標簽。

這是我已經在做的相關代碼:

def set_tag_styles(self):
    self.myTextWidget.tag_config("bold", font=[self.d["font"][0], self.d["font"][1], "bold"])
    self.myTextWidget.tag_config("italic", font=[self.d["font"][0], self.d["font"][1], "italic"])
    self.myTextWidget.tag_config("underline", font=[self.d["font"][0], self.d["font"][1], "underline"])
    self.myTextWidget.tag_config("overstrike", font=[self.d["font"][0], self.d["font"][1], "overstrike"])
def invert_tag(self, start, end=None, tag=SEL, w=None):
    #This just makes text without the tag have the tag and text with the tag not have the tag anymore.
    if w==None:
        w=self.myTextWidget
    i=0
    if end==None:
        if tag in w.tag_names(start):
            w.tag_remove(tag, start)
        else:
            w.tag_add(tag, start)
    else:
        while w.compare(start+"+"+str(i)+"c", "<", end):
            if tag in w.tag_names(start+"+"+str(i)+"c"):
                w.tag_remove(tag, start+"+"+str(i)+"c")
            else:
                w.tag_add(tag, start+"+"+str(i)+"c")
            i+=1
    self.set_tag_styles()
def bold_text(self, event=None):
    try:
        self.invert_tag("sel.first", "sel.last", "bold")
    except:
        if self.myTextWidget.get("insert wordstart") in {" ", "\n", "\t", "\r", " "}:
            pass
        else:
            self.invert_tag("insert wordstart", "insert wordend", "bold")
    return "break"
def italic_text(self, event=None):
    try:
        self.invert_tag("sel.first", "sel.last", "italic")
    except:
        if self.myTextWidget.get("insert wordstart") in {" ", "\n", "\t", "\r", " "}:
            pass
        else:
            self.invert_tag("insert wordstart", "insert wordend", "italic")
    return "break"

編輯:對於那些有興趣(不想從頭開始編寫所有代碼)的人,這是我為使其工作而做的代碼(使用布萊恩·奧克利的答案作為指導):

self.style_tags={"bold", "italic", "underline", "overstrike", "bold italic", "bold italic underline", "bold italic underline overstrike", "italic underline", "italic overstrike", "italic underline overstrike", "underline overstrike", "bold underline", "bold underline overstrike", "bold overstrike", "bold italic overstrike"};
    …
    def clear_multiple_styles(self, pos, w=None):
        #This gets rid of all multi-style tags (like "bold italic underline").
        if w==None:
            w=self.myTextWidget;
        for x in self.style_tags:
            s=Switch(); #This is my version of a switch statement (so I don't have to type my compare variable every time), with added flexibility.
            s.switch(x);
            if s.neq("bold", "italic", "underline", "overstrike"): #This means, if x isn't equal to any of them
                if x in w.tag_names(pos):
                    w.tag_remove(x, pos);
    def update_style(self, pos, w=None):
        #This updates the styles of an index to take care of overlapping style tags.
        if w==None:
            w=self.myTextWidget;
        self.clear_multiple_styles(pos, w);
        s=Switch();
        s.switch(w.tag_names(pos));
        if s.ins("bold", "italic", "underline", "overstrike"): #i.e. If these args are all in w.tag_names(pos)
            w.tag_add("bold italic underline overstrike", pos);
        elif s.ins("bold", "italic", "underline"):
            w.tag_add("bold italic underline", pos);
        elif s.ins("bold", "italic", "overstrike"):
            w.tag_add("bold italic overstrike", pos);
        elif s.ins("bold", "italic"):
            w.tag_add("bold italic", pos);
        elif s.ins("bold", "underline", "overstrike"):
            w.tag_add("bold underline overstrike", pos);
        elif s.ins("bold", "underline"):
            w.tag_add("bold underline", pos);
        elif s.ins("bold", "overstrike"):
            w.tag_add("bold overstrike", pos);
        elif s.ins("italic", "underline", "overstrike"):
            w.tag_add("italic underline overstrike", pos);
        elif s.ins("italic", "underline"):
            w.tag_add("italic underline", pos);
        elif s.ins("italic", "overstrike"):
            w.tag_add("italic overstrike", pos);
        elif s.ins("underline", "overstrike"):
            w.tag_add("underline overstrike", pos);
    def invert_style_tag(self, start, end=None, tag="bold", w=None):
        if w==None:
            w=self.myTextWidget;
        i=0;
        if end==None:
            if tag in w.tag_names(start):
                w.tag_remove(tag, start);
            else:
                w.tag_add(tag, start);
            self.update_style(start);
        else:
            while w.compare(start+"+"+str(i)+"c", "<", end):
                if tag in w.tag_names(start+"+"+str(i)+"c"):
                    w.tag_remove(tag, start+"+"+str(i)+"c");
                else:
                    w.tag_add(tag, start+"+"+str(i)+"c");
                self.update_style(start+"+"+str(i)+"c");
                i+=1;
        self.set_tag_styles();
    def set_tag_styles(self):
        single_styles={"bold", "italic", "underline", "overstrike"};
        for x in self.style_tags:
            x_list=x.split();
            self.myTextWidget.tag_config(x, font=[self.d["font"][0], self.d["font"][1]]+x_list); #You can add lists together to get the extra arguments in.
            for y in single_styles:
                if x not in single_styles:
                    self.myTextWidget.tag_raise(x); #Gives the multi-style tag higher priority than existing single-style tags
    def style_text(self, style):
        try:
            self.invert_style_tag("sel.first", "sel.last", style);
        except:
            if self.myTextWidget.get("insert wordstart") in {" ", "\n", "\t", "\r", " "}:
                pass;
            else:
                self.invert_style_tag("insert wordstart", "insert wordend", style);
    def bold_text(self, event=None):
        self.style_text("bold");
        return "break";
    def italic_text(self, event=None):
        self.style_text("italic");
        return "break";
    def underline_text(self, event=None):
        self.style_text("underline");
        return "break";
    def overstrike_text(self, event=None):
        self.style_text("overstrike");
        return "break";

對於那些想要我的Switch類代碼(而不是將其轉換為標准表達式)的人來說,這里是(如果抱歉,這對您來說太多代碼了):

class Switch:
    def switch(self, item):
        self.item=item;
    def case(self, values, operator="=="):
        #values must be a list, set, tuple or other sequence. This is to allow one not to have to define operator. If you don't like this, use the other methods.
        if operator in "==":
            return self.eq(*values);
        elif operator=="!" or operator=="!=":
            return self.neq(*values);
        elif operator==">":
            return self.gr(*values);
        elif operator=="<":
            return self.ls(*values);
        elif operator==">=":
            return self.gre(*values);
        elif operator=="<=":
            return self.lse(*values);
        elif operator in "range" and operator[0]=="r":
            if len(values)!=2:
                raise ValueError("There must be two and only two values in a range.");
            return self.range(values[0], values[1]);
        elif operator in "nrange" and operator[0]=="n":
            if len(values)!=2:
                raise ValueError("There must be two and only two values in an nrange.");
            return self.nrange(values[0], values[1]);
        else:
            raise ValueError("The operator "+operator+" is not currently defined.");
    def ins(self, *values):
        #If all the values are part of the string or sequence, self.item, return True. Else return False.
        #Note: It doesn't take into account that "" is in every string and some tuples.
        for x in values:
            if x not in self.item:
                return False;
        return True;
    def eq(self, *values):
        #Equal to
        return self.item in values;
    def gr(self, *values):
        #Greater than
        for x in values:
            if self.item<=x:
                return False;
        return True;
    def gre(self, *values):
        #Greater than or equal to
        for x in values:
            if self.item<x:
                return False;
        return True;
    def ls(self, *values):
        #Less than
        for x in values:
            if self.item>=x:
                return False;
        return True;
    def lse(self, *values):
        #Less than or equal to
        for x in values:
            if self.item>x:
                return False;
        return True;
    def neq(self, *values):
        return self.item not in values;
    def range(self, min, max):
        return self.item in range(min, max) or max==self.item or min==self.item;
    def nrange(self, min, max):
        return self.item not in range(min, max) and max!=self.item and min!=self.item;

問題不在於標簽本身本身是重疊的,而是您正在嘗試使用重疊的字體。 如果兩個標簽定義了font屬性,則僅使用優先級較高的標簽的字體。

唯一的選擇是為“粗斜體”創建第三個標記,該標記已定義了適當的字體。 然后,當您想要粗體顯示或斜體顯示時,您需要有一種特殊情況以適當地使用第三個標記(即:如果范圍中沒有標記,則添加斜體,如果其具有粗體,則將其更改為粗體) -斜體等)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM