sidnical
sidnical

Reputation: 459

Stop tkinter frame from being pushed off screen

I have a tk window with 3 frames, a left side that works like a tree structure with labels that will be added and removed with .grid() and grid_remove(), a right frame that will display information about these items, and a bottom frame that will hold buttons. If I expand too many items on the left frame(lframe) it pushes the bottom frame (bframe) out of view. I would rather the bottom frame stop when it gets to the edge of the window and the scrollbar for the lframe be used to view the items for lframe.

Here is a simple example of what im seeing. As you click the button more label widgets will be created and it will push the bframe out of view.

from tkinter import *

main = Tk()

canvas = Canvas(main)
canvas.grid(row=0, column=0)
canvas.configure(scrollregion=canvas.bbox("all"))
lframe = Frame(canvas)
lframe.grid(row=0, column=1)


sbar = Scrollbar(canvas)
sbar.config(command=canvas.yview)
canvas.config(yscrollcommand=sbar.set)
sbar.grid(row=0, column=0, sticky=NSEW)

rframe = Frame(main)
rframe.grid(row=0, column=1, sticky=N)

bframe = Frame(main)
bframe.grid(row=1, column=1)


cnt = 1
def addmore():
    global cnt

    test = Label(lframe, text='this \nis \nthe \nLEFT \nframe\nthis \nis \nthe \nLEFT \nframe\nthis \nis \nthe \nLEFT \nframe\nthis \nis \nthe \nLEFT \nframe\nthis \nis \nthe \nLEFT \nframe\n')
    test.grid(row=cnt, column=0)
    cnt += 1
    lframe.update()


llbl = Label(lframe, text='this \nis \nthe \nLEFT \nframe')
llbl.grid()

rlbl = Label(rframe, text='this is the RIGHT frame')
rlbl.grid()
btn = Button(rframe, text='click me', command=addmore)
btn.grid(row=1, column=0, sticky=N)
blbl = Label(bframe, text='this is the BOTTOM frame', bg="yellow")
blbl.grid(row=0)


main.mainloop()

Question 1: How can I stop the bframe from pushing off the screen? I want it to stop when it gets to the bottom of main and the labels in lframe start pushing out of view behind bframe. Then the user would use the scrollbar to view the other items in lframe.

Question 2: I wont know if my scrollbar is configured correctly until I can get the lframe to stop pushing off the screen. If its not setup right, what do I need to change?

Upvotes: 1

Views: 2948

Answers (1)

Mike - SMT
Mike - SMT

Reputation: 15226

Here is an example of how you would set this scrolling canvas up with weights in the main frame. Its not perfect but it should be enough to help.

import tkinter as tk

class Example(tk.Frame):
    def __init__(self):

        tk.Frame.__init__(self)

        self.canvas = tk.Canvas(self, borderwidth=0, width = 50, height = 100)
        self.lframe = tk.Frame(self.canvas, width=10)
        self.sbar = tk.Scrollbar(self, orient="vertical", command=self.canvas.yview)
        self.canvas.configure(yscrollcommand=self.sbar.set)

        self.sbar.grid(row=0, column=0, rowspan=2, sticky="nsw")
        self.canvas.grid(row=0, column=1, rowspan=2, sticky="nsew")
        self.canvas.create_window((2,2), window=self.lframe, anchor="ne", 
                                  tags="self.lframe")

        self.lframe.bind("<Configure>", self.onFrameConfigure)
        self.rframe = tk.Frame(self)
        self.rframe.grid(row=0, column=2, sticky="n")

        self.bframe = tk.Frame(self)
        self.bframe.grid(row=1, column=2)

        llbl = tk.Label(self.lframe, text='this \nis \nthe \nLEFT \nframe')
        llbl.grid(row = 0, column = 0)

        rlbl = tk.Label(self.rframe, text='this is the RIGHT frame')
        rlbl.grid(row = 0, column = 0)
        btn = tk.Button(self.rframe, text='click me', command=self.addmore)
        btn.grid(row=1, column=0, sticky="n")
        blbl = tk.Label(self.bframe, text='this is the BOTTOM frame', bg="yellow")
        blbl.grid(row = 2, column = 0, sticky = "s")

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

        self.cnt = 1

    def addmore(self):
        test = tk.Label(self.lframe, text='this \nis \nthe \nLEFT \nframe\nthis \nis \nthe \nLEFT \nframe\nthis \nis \nthe \nLEFT \nframe\nthis \nis \nthe \nLEFT \nframe\nthis \nis \nthe \nLEFT \nframe\n')
        test.grid(row=self.cnt, column=0)
        self.cnt += 1

    def onFrameConfigure(self, event):
        '''Reset the scroll region to encompass the inner frame'''
        self.canvas.configure(scrollregion=self.canvas.bbox("all"))

if __name__ == "__main__":
    root=tk.Tk()
    Example().grid(row=0, column=0)
    root.mainloop()

Upvotes: 1

Related Questions