Search code examples
python-3.xtkintertkinter-text

Is there a way to set a wrap length on a Tkinter Text Widget?


Question

I am trying to make a text editor in Tkinter. If a large single-line file is opened, it lags massively and stops responding. Is there a way to set a wrap length for a text widget? I have scroll bars and I don't want to have the characters wrap at the end of the text box. I want it to wrap after a certain number of characters.

Is this possible? If so, how can I do it?

I am using Python 3.9.6 on 64-bit Windows 10.

What I have tried

I have tried using wraplength= in the function, but that doesn't work. I have also searched for this question and found nothing.

Code

from tkinter import *
root = Tk()
root.title('Notpad [new file]')
root.geometry('1225x720')
      
txt = Text(root,width=150,height=40,wrap=NONE)
txt.place(x=0,y=0)
#Buttons here
        
scr = Scrollbar(root)
scr.pack(side='right',fill='y',expand=False)
txt.config(yscrollcommand=scr.set)
scr.config(command=txt.yview)
scr1 = Scrollbar(root,orient='horizontal')
scr1.pack(side='bottom',fill='x',expand=False)
txt.config(xscrollcommand=scr1.set)
scr1.config(command=txt.xview)
     
        
root.mainloop()

Solution

  • There is no wraplength option in tkinter Text widget. However you can simulate the effect using rmargin option of tag_configure().

    Below is an example with a custom text widget using rmargin option:

    import tkinter as tk
    from tkinter import font
    
    class MyText(tk.Text):
        def __init__(self, master=None, **kw):
            self.wraplength = kw.pop('wraplength', 80)
            # create an instance variable of type font.Font
            # it is required because Font.measure() is used later
            self.font = font.Font(master, font=kw.pop('font', ('Consolas',12)))
            super().__init__(master, font=self.font, **kw)
            self.update_rmargin() # keep monitor and update "rmargin"
    
        def update_rmargin(self):
            # determine width of a character of current font
            char_w = self.font.measure('W')
            # calculate the "rmargin" in pixel
            rmargin = self.winfo_width() - char_w * self.wraplength
            # set up a tag with the "rmargin" option set to above value
            self.tag_config('rmargin', rmargin=rmargin, rmargincolor='#eeeeee')
            # apply the tag to all the content
            self.tag_add('rmargin', '1.0', 'end')
            # keep updating the "rmargin"
            self.after(10, self.update_rmargin)
    
    root = tk.Tk()
    
    textbox = MyText(root, width=100, font=('Consolas',12), wrap='word', wraplength=90)
    textbox.pack(fill='both', expand=1)
    
    # load current file
    with open(__file__) as f:
        textbox.insert('end', f.read())
    
    root.mainloop()
    

    Note that I have used after() so that even there are changes on the content, the rmargin option is applied to updated content.

    Note also that it may not be an efficient way, but it shows a possible way.