Home > Enterprise >  Tkinter frame shrinks and then grows when width and height is given
Tkinter frame shrinks and then grows when width and height is given

Time:04-15

I have created a frame that holds a specialized text widget. In my app I have a button to change the color mode from light to dark and vice versa. everything works quite well with the color mode change except the specialized text widget. I have narrowed down the problem and have found that it is the width=134, height=30 that is causing the problem. No idea why though. Any ideas?

Code to reproduce problem:

from tkinter import *
class ultra_text(Frame):
    def __init__(self, *args, **kwargs):
        self.window = kwargs.pop("window", None)
        self.color_mode = kwargs.pop("color_mode")
        Frame.__init__(self, *args, **kwargs)
        if "height" and "width" in kwargs:
            self.text = Text(self, height=kwargs["height"], width=kwargs["width"], borderwidth=2, relief=RIDGE, wrap=NONE, undo=True, font=("Courier New bold", 15))
        else:
            self.text = Text(self, font=("Courier New bold", 15), wrap="none", undo=True, borderwidth=2, relief=RIDGE, width=120, height=30)

        self.scrollbar = Scrollbar(self, orient=VERTICAL, command=self.text.yview)
        self.text.configure(yscrollcommand=self.scrollbar.set)


        self.numberLines = TextLineNumbers(self, width=40)
        self.numberLines.attach(self.text)

        self.scrollbar.pack(side=RIGHT, fill=Y)
        self.numberLines.pack(side=LEFT, fill=Y, padx=(5, 0))
        self.text.pack(side=RIGHT, fill=BOTH, expand=True)

        self.text.bind("<Key>", self.onPressDelay)
        self.text.bind("<Button-1>", self.numberLines.redraw)
        self.scrollbar.bind("<Button-1>", self.onScrollPress)
        self.text.bind("<MouseWheel>", self.onPressDelay)

        self.window.bind("<KeyRelease>", self.redraw())

#Place tag_config here

    def change_color(self, new_color):
        if new_color == "Dark":
            bg = "black"
            fg = "white"
        else:
            bg = "white"
            fg = "black"
        self.text.config(bg=bg, fg=fg, insertbackground=fg)
        self.numberLines.config(bg=bg)
    
    def onScrollPress(self, *args):
        self.scrollbar.bind("<B1-Motion>", self.numberLines.redraw)

    def onScrollRelease(self, *args):
        self.scrollbar.unbind("<B1-Motion>", self.numberLines.redraw)

    def onPressDelay(self, *args):
        self.after(2, self.numberLines.redraw)

    def get(self, *args, **kwargs):
        return self.text.get(*args, **kwargs)

    def insert(self, *args, **kwargs):
        return self.text.insert(*args, **kwargs)

    def delete(self, *args, **kwargs):
        return self.text.delete(*args, **kwargs)

    def index(self, *args, **kwargs):
        return self.text.index(*args, **kwargs)

    def redraw(self):
        self.numberLines.redraw()

class TextLineNumbers(Canvas):
    def __init__(self, *args, **kwargs):
        Canvas.__init__(self, *args, **kwargs, highlightthickness=0)
        self.textwidget = None

    def attach(self, text_widget):
        self.textwidget = text_widget

    def redraw(self, *args):
        '''redraw line numbers'''
        self.delete("all")

        i = self.textwidget.index("@0,0")
        while True :
            dline= self.textwidget.dlineinfo(i)
            if dline is None: break
            y = dline[1]
            linenum = str(i).split(".")[0]
            self.create_text(2, y, anchor="nw", text=linenum, fill="#808090") #606366
            i = self.textwidget.index("%s 1line" % i)
if __name__ == "__main__":
    window = Tk()
    color_mode = "Light"
    window.geometry("%dx%d 0 0" % (window.winfo_screenwidth(), window.winfo_screenheight()))
    my_text = ultra_text(window, window = window, color_mode="Dark", width=134, height=30)#Problem is here <- get rid of ", width=134, height=30" and it works. Keep it and it has the bug. How do I get rid of the bug while keeping the width and height?
    my_text.place(relx=.5, rely=.5, anchor=CENTER)
    def change_color_mode():
        global my_text
        global color_mode
        if color_mode == "Dark":
            color_mode = "Light"
        else:
            color_mode = "Dark"
        if color_mode == "Dark":
            bg = "black"
        else:
            bg = "white"
        my_text.change_color(color_mode) #This part is fine and does the bulk of the color_changing
        my_text.configure(bg=bg)
        change_color_mode_button.config(highlightbackground=bg)
        window.configure(bg=bg)
    change_color_mode_button = Button(window, text="Change Color Mode", command=change_color_mode)
    change_color_mode_button.pack()
    window.mainloop()

CodePudding user response:

I figured out the solution; if we remove the width and height from the main part it keeps its size because of the else statement but gets rid of the bug.

Code:


from tkinter import *
class ultra_text(Frame):
    def __init__(self, *args, **kwargs):
        self.window = kwargs.pop("window", None)
        self.color_mode = kwargs.pop("color_mode")
        Frame.__init__(self, *args, **kwargs)
        if "height" and "width" in kwargs:
            self.text = Text(self, height=kwargs["height"], width=kwargs["width"], borderwidth=2, relief=RIDGE, wrap=NONE, undo=True, font=("Courier New bold", 15))
        else:
            self.text = Text(self, font=("Courier New bold", 15), wrap="none", undo=True, borderwidth=2, relief=RIDGE, width=120, height=30)

        self.scrollbar = Scrollbar(self, orient=VERTICAL, command=self.text.yview)
        self.text.configure(yscrollcommand=self.scrollbar.set)


        self.numberLines = TextLineNumbers(self, width=40)
        self.numberLines.attach(self.text)

        self.scrollbar.pack(side=RIGHT, fill=Y)
        self.numberLines.pack(side=LEFT, fill=Y, padx=(5, 0))
        self.text.pack(side=RIGHT, fill=BOTH, expand=True)

        self.text.bind("<Key>", self.onPressDelay)
        self.text.bind("<Button-1>", self.numberLines.redraw)
        self.scrollbar.bind("<Button-1>", self.onScrollPress)
        self.text.bind("<MouseWheel>", self.onPressDelay)

        self.window.bind("<KeyRelease>", self.redraw())

#Place tag_config here

    def change_color(self, new_color):
        if new_color == "Dark":
            bg = "black"
            fg = "white"
        else:
            bg = "white"
            fg = "black"
        self.text.config(bg=bg, fg=fg, insertbackground=fg)
        self.numberLines.config(bg=bg)
    
    def onScrollPress(self, *args):
        self.scrollbar.bind("<B1-Motion>", self.numberLines.redraw)

    def onScrollRelease(self, *args):
        self.scrollbar.unbind("<B1-Motion>", self.numberLines.redraw)

    def onPressDelay(self, *args):
        self.after(2, self.numberLines.redraw)

    def get(self, *args, **kwargs):
        return self.text.get(*args, **kwargs)

    def insert(self, *args, **kwargs):
        return self.text.insert(*args, **kwargs)

    def delete(self, *args, **kwargs):
        return self.text.delete(*args, **kwargs)

    def index(self, *args, **kwargs):
        return self.text.index(*args, **kwargs)

    def redraw(self):
        self.numberLines.redraw()

class TextLineNumbers(Canvas):
    def __init__(self, *args, **kwargs):
        Canvas.__init__(self, *args, **kwargs, highlightthickness=0)
        self.textwidget = None

    def attach(self, text_widget):
        self.textwidget = text_widget

    def redraw(self, *args):
        '''redraw line numbers'''
        self.delete("all")

        i = self.textwidget.index("@0,0")
        while True :
            dline= self.textwidget.dlineinfo(i)
            if dline is None: break
            y = dline[1]
            linenum = str(i).split(".")[0]
            self.create_text(2, y, anchor="nw", text=linenum, fill="#808090") #606366
            i = self.textwidget.index("%s 1line" % i)

if __name__ == "__main__":
    window = Tk()
    color_mode = "Light"
    window.geometry("%dx%d 0 0" % (window.winfo_screenwidth(), window.winfo_screenheight()))
    my_text = ultra_text(window, window = window, color_mode="Dark")
    my_text.place(relx=.5, rely=.5, anchor=CENTER)
    def change_color_mode():
        global my_text
        global color_mode
        if color_mode == "Dark":
            color_mode = "Light"
        else:
            color_mode = "Dark"
        if color_mode == "Dark":
            bg = "black"
        else:
            bg = "white"
        my_text.change_color(color_mode) #This part is fine and does the bulk of the color_changing
        my_text.configure(bg=bg)
        change_color_mode_button.config(highlightbackground=bg)
        window.configure(bg=bg)
    change_color_mode_button = Button(window, text="Change Color Mode", command=change_color_mode)
    change_color_mode_button.pack()
    window.mainloop()

It seems that because it is inputting the width and height from kwargs that it alters the width and height variables to have a problem but I can't be quite sure.

  • Related