simple text browser for idle a scrollbar that is automatically hidden when not needed only the grid geometry manager is supported display text with scrollbars def initself master wrapnone kwargs super initmaster kwargs text self text textself wrapwrap text gridrow0 column0 stickynsew self gridrowconfigure0 weight1 self gridcolumnconfigure0 weight1 vertical scrollbar self yscroll autohidescrollbarself orientvertical takefocusfalse commandtext yview self yscroll gridrow0 column1 stickyns text yscrollcommand self yscroll set horizontal scrollbar only when wrap is set to none if wrap none self xscroll autohidescrollbarself orienthorizontal takefocusfalse commandtext xview self xscroll gridrow1 column0 stickyew text xscrollcommand self xscroll set else self xscroll none class viewframeframe display textframe and close button def initself parent contents wrap word super initparent self parent parent self bind return self ok self bind escape self ok self textframe scrollabletextframeself reliefsunken height700 text self text self textframe text text insert 1 0 contents text configurewrapwrap highlightthickness0 state disabled colorconfigtext text focusset self buttonok buttonok button self text close commandself ok takefocusfalse self textframe packside top expandtrue fill both buttonok packside bottom def okself eventnone show the given text in a scrollable window with a close button if modal is left true users cannot interact with other windows until the textview window is closed parent parent of this dialog title string which is title of popup dialog contents text to display in dialog wrap type of text wrapping to use word char or none htest bool change box location when running htest utest bool don t waitwindow when running unittest place dialog below parent if running htest dismiss text viewer dialog if self ismodal self grabrelease self destroy def viewtextparent title contents modaltrue wrap word utestfalse return viewwindowparent title contents modal wrapwrap utestutest def viewfileparent title filename encoding modaltrue wrap word utestfalse try with openfilename encodingencoding as file contents file read except oserror showerrortitle file load error messagef unable to load file filename r parentparent except unicodedecodeerror as err showerrortitle unicode decode error messagestrerr parentparent else return viewtextparent title contents modal wrapwrap utestutest return none if name main from unittest import main main idlelib idletest testtextview verbosity2 exitfalse from idlelib idletest htest import run runviewwindow a scrollbar that is automatically hidden when not needed only the grid geometry manager is supported display text with scrollbar s create a frame for textview master master widget for this frame wrap type of text wrapping to use word char or none all parameters except for wrap are passed to frame __init__ the text widget is accessible via the text attribute note changing the wrapping mode of the text widget after instantiation is not supported vertical scrollbar horizontal scrollbar only when wrap is set to none create a frame for viewing text with a close button parent parent widget for this frame contents text to display wrap type of text wrapping to use word char or none the text widget is accessible via the text attribute dismiss text viewer dialog show the given text in a scrollable window with a close button if modal is left true users cannot interact with other windows until the textview window is closed parent parent of this dialog title string which is title of popup dialog contents text to display in dialog wrap type of text wrapping to use word char or none _htest bool change box location when running htest _utest bool don t wait_window when running unittest place dialog below parent if running htest dismiss text viewer dialog create text viewer for given text parent parent of this dialog title string which is the title of popup dialog contents text to display in this dialog wrap type of text wrapping to use word char or none modal controls if users can interact with other windows while this dialog is displayed _utest bool controls wait_window on unittest create text viewer for text in filename return error message if file cannot be read otherwise calls view_text with contents of the file
from tkinter import Toplevel, Text, TclError,\
    HORIZONTAL, VERTICAL, NS, EW, NSEW, NONE, WORD, SUNKEN
from tkinter.ttk import Frame, Scrollbar, Button
from tkinter.messagebox import showerror

from idlelib.colorizer import color_config


class AutoHideScrollbar(Scrollbar):
    
    def set(self, lo, hi):
        if float(lo) > 0.0 or float(hi) < 1.0:
            self.grid()
        else:
            self.grid_remove()
        super().set(lo, hi)

    def pack(self, **kwargs):
        raise TclError(f'{self.__class__.__name__} does not support "pack"')

    def place(self, **kwargs):
        raise TclError(f'{self.__class__.__name__} does not support "place"')


class ScrollableTextFrame(Frame):
    

    def __init__(self, master, wrap=NONE, **kwargs):
        
        super().__init__(master, **kwargs)

        text = self.text = Text(self, wrap=wrap)
        text.grid(row=0, column=0, sticky=NSEW)
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)

        
        self.yscroll = AutoHideScrollbar(self, orient=VERTICAL,
                                         takefocus=False,
                                         command=text.yview)
        self.yscroll.grid(row=0, column=1, sticky=NS)
        text['yscrollcommand'] = self.yscroll.set

        
        if wrap == NONE:
            self.xscroll = AutoHideScrollbar(self, orient=HORIZONTAL,
                                             takefocus=False,
                                             command=text.xview)
            self.xscroll.grid(row=1, column=0, sticky=EW)
            text['xscrollcommand'] = self.xscroll.set
        else:
            self.xscroll = None


class ViewFrame(Frame):
    "Display TextFrame and Close button."
    def __init__(self, parent, contents, wrap='word'):
        
        super().__init__(parent)
        self.parent = parent
        self.bind('<Return>', self.ok)
        self.bind('<Escape>', self.ok)
        self.textframe = ScrollableTextFrame(self, relief=SUNKEN, height=700)

        text = self.text = self.textframe.text
        text.insert('1.0', contents)
        text.configure(wrap=wrap, highlightthickness=0, state='disabled')
        color_config(text)
        text.focus_set()

        self.button_ok = button_ok = Button(
                self, text='Close', command=self.ok, takefocus=False)
        self.textframe.pack(side='top', expand=True, fill='both')
        button_ok.pack(side='bottom')

    def ok(self, event=None):
        
        self.parent.destroy()


class ViewWindow(Toplevel):
    "A simple text viewer dialog for IDLE."

    def __init__(self, parent, title, contents, modal=True, wrap=WORD,
                 *, _htest=False, _utest=False):
        
        super().__init__(parent)
        self['borderwidth'] = 5
        
        x = parent.winfo_rootx() + 10
        y = parent.winfo_rooty() + (10 if not _htest else 100)
        self.geometry(f'=750x500+{x}+{y}')

        self.title(title)
        self.viewframe = ViewFrame(self, contents, wrap=wrap)
        self.protocol("WM_DELETE_WINDOW", self.ok)
        self.button_ok = button_ok = Button(self, text='Close',
                                            command=self.ok, takefocus=False)
        self.viewframe.pack(side='top', expand=True, fill='both')

        self.is_modal = modal
        if self.is_modal:
            self.transient(parent)
            self.grab_set()
            if not _utest:
                self.wait_window()

    def ok(self, event=None):
        
        if self.is_modal:
            self.grab_release()
        self.destroy()


def view_text(parent, title, contents, modal=True, wrap='word', _utest=False):
    
    return ViewWindow(parent, title, contents, modal, wrap=wrap, _utest=_utest)


def view_file(parent, title, filename, encoding, modal=True, wrap='word',
              _utest=False):
    
    try:
        with open(filename, encoding=encoding) as file:
            contents = file.read()
    except OSError:
        showerror(title='File Load Error',
                  message=f'Unable to load file {filename!r} .',
                  parent=parent)
    except UnicodeDecodeError as err:
        showerror(title='Unicode Decode Error',
                  message=str(err),
                  parent=parent)
    else:
        return view_text(parent, title, contents, modal, wrap=wrap,
                         _utest=_utest)
    return None


if __name__ == '__main__':
    from unittest import main
    main('idlelib.idle_test.test_textview', verbosity=2, exit=False)

    from idlelib.idle_test.htest import run
    run(ViewWindow)