0

I am having trouble getting tkinter.Canvas to stay within the bounds of its row and column in the grid manager.

This is how it looks to begin with

As required, the scrollbars appear when the window is shrunk enough that the text won't all fit

When the scrollbars are used, it becomes evident that the canvas is still behind the scrollbars

I need to figure out how to adjust the canvas so that it stays within row 0, column 0 of the grid manager and doesn't spill over to row 1 and column 1 or further. The following is the main code that has the problem in it.

import tkinter as tk

from AutoScrollbar import *

class ScrollText(tk.Frame):

    def __init__(self, parent, writing, wrap, *args, **kwargs):

        tk.Frame.__init__(self, parent, *args, **kwargs)

        self.rowconfigure(0, weight = 1)
        self.columnconfigure(0, weight = 1)

        self.xscrlbr = AutoScrollbar(self, orient = 'horizontal')
        self.xscrlbr.grid(row = 1, column = 0, sticky = 'we')
        self.yscrlbr = AutoScrollbar(self)
        self.yscrlbr.grid(row = 0, column = 1, sticky = 'ns')

        self.canv = tk.Canvas(self)
        self.canv.grid(column = 0, row = 0, sticky = 'news')

        self.xscrlbr.config(command = self.canv.xview)
        self.yscrlbr.config(command = self.canv.yview)

        self.text = tk.Label(self, text = writing, wraplength = wrap,
                             justify = 'left')
        self.text_id = self.canv.create_window(0, 0,
                                window = self.text, anchor = 'nw')
        self.canv.config(xscrollcommand = self.xscrlbr.set,
                         yscrollcommand = self.yscrlbr.set,
                         scrollregion = (0, 0, 100, 100))

        self.yscrlbr.lift(self.text)
        self.xscrlbr.lift(self.text)

        self.canv.bind('<Configure>', self.OnCanvasConfigure)
        self.text.bind('<Configure>', self._configure_window)

    def OnCanvasConfigure(self, event):

        width = max(event.width, self.text.winfo_reqwidth())
        height = max(event.height, self.text.winfo_reqheight())

        self.canv.itemconfigure(self.text_id, width = width, height = height)

    def _configure_window(self, event):
      
        size = (self.text.winfo_reqwidth(), self.text.winfo_reqheight())
        self.canv.config(scrollregion = '0 0 %s %s' % size)

The following is the AutoScrollbar code, though the problem behavior is the same with the normal tkinter.Scrollbar as well, so this is not the issue.

import tkinter as tk

class AutoScrollbar(tk.Scrollbar):

    def set(self, low, high):

        if float(low) <= 0.0 and float(high) >= 1.0:

            self.tk.call("grid", "remove", self)

        else:

            self.grid()

        tk.Scrollbar.set(self, low, high)

Finally, here is the sample code that I am using to call it: No problem here either as far as I can tell.

import tkinter as tk
from ScrollText import *

class Template(tk.Tk):

    def __init__(self):

        tk.Tk.__init__(self)

        self.state('zoomed')

        self.rowconfigure(0, weight = 1)
        self.columnconfigure(0, weight = 1)

        message = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Pellentesque elit ullamcorper dignissim cras. Venenatis lectus magna fringilla urna. Augue lacus viverra vitae congue eu consequat ac felis. Arcu bibendum at varius vel pharetra vel turpis nunc eget. Pellentesque nec nam aliquam sem et tortor consequat. Dignissim suspendisse in est ante in. Diam volutpat commodo sed egestas egestas fringilla phasellus. Est placerat in egestas erat imperdiet sed euismod nisi porta. Turpis tincidunt id aliquet risus feugiat in ante. Tristique nulla aliquet enim tortor at. Nibh ipsum consequat nisl vel pretium. Ultricies mi quis hendrerit dolor magna eget est lorem ipsum. Leo vel orci porta non pulvinar neque laoreet suspendisse interdum. Volutpat odio facilisis mauris sit amet massa vitae tortor. Vel pretium lectus quam id. Egestas integer eget aliquet nibh praesent. Senectus et netus et malesuada fames ac. Iaculis eu non diam phasellus vestibulum lorem. Ut eu sem integer vitae justo eget magna fermentum."

        scrollableText = ScrollText(self, message, 500)
        scrollableText.grid(row = 0, column = 0, sticky = 'news', pady = 20, padx = 20)

if __name__ == '__main__':

    test = Template()
    test.mainloop()
Amy
  • 5
  • 1
  • Not really helping your problem but did you know that there is a [`ScrolledText`](https://stackoverflow.com/a/59334753/11106801) widget that you can use. Also is there a specific reason for why you are using `tkinter.Canvas` instead of `tkinter.Text`? – TheLizzard Apr 04 '21 at 22:15
  • I couldn't figure out how to make ScrolledText work the way I wanted it to. Firstly, it has to look exactly how it is in the images. Second, is there an option that I'm missing that makes the scrollbars disappear when they're unneeded (that is, the text completely fits on the screen). Third, I was only able to add the vertical scrollbar. How do I add the horizontal scrollbar in the ScrolledText widget? I had to use Canvas because the Scrollbar didn't work with Label. – Amy Apr 04 '21 at 22:21
  • You can't add a horizontal scrollbar when using `ScrolledText` but look at its source code. It uses a `tkinter.Text` with `tkinter.Scrollbar`. If you replace the `tkinter.Scrollbar` with your `AutoScrollbar` and add the horizontal scrollbar (quite simple) you should get the same thing as in the pictures above. If you use `tkinter.Canvas`, you would be able to let the user type in the textbox and you will be missing out on a lot of functionality. – TheLizzard Apr 04 '21 at 22:28

1 Answers1

1

You are creating the label as a child of the frame, but then embedding it inside a canvas. If you're going to embed a widget inside a canvas, it should be a child of the canvas.

self.text = tk.Label(self.canv, text = writing, wraplength = wrap,justify = 'left')
#                    ^^^^^^^^^
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Thank you. I can't believe that it was that simple. Everything I looked at before said that the widget had to have the same parent as the canvas. – Amy Apr 04 '21 at 22:24