I have the current code (cut down from the original) - this snippet is also available here.
import tkinter as tk
import tkinter.ttk as ttk
class ScrolledFrame(tk.Frame):
def __init__(self, master, **kw):
tk.Frame.__init__(self, master, **kw)
vsb = tk.Scrollbar(self, orient='vertical')
vsb.grid(column=1, row=0, sticky='ns')
hsb = tk.Scrollbar(self, orient='horizontal')
hsb.grid(column=0, row=1, sticky='ew')
self.canvas = canvas = tk.Canvas(self, bd=0, highlightthickness=0,
yscrollcommand=vsb.set, xscrollcommand=hsb.set)
canvas.grid(row=0, column=0, sticky='nsew')
#canvas.configure(scrollregion=canvas.bbox('all'))
vsb.config(command=canvas.yview)
hsb.config(command=canvas.xview)
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
# reset the view
canvas.xview_moveto(0)
canvas.yview_moveto(0)
self.interior = interior = tk.Frame(canvas)
interior_id = canvas.create_window(0, 0, window=interior,
anchor='nw')
def _configure_interior(event):
size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
canvas.config(scrollregion="0 0 %s %s" % size)
if interior.winfo_reqwidth() != canvas.winfo_width():
canvas.config(width=interior.winfo_reqwidth())
interior.bind('<Configure>', _configure_interior)
def _configure_canvas(event):
if interior.winfo_reqwidth() != canvas.winfo_width():
canvas.itemconfigure(interior_id, width=canvas.winfo_width())
canvas.bind('<Configure>', _configure_canvas)
if __name__ == '__main__':
root = tk.Tk()
main_frame = ScrolledFrame(root)
main_frame.grid(row=0, column=0, sticky='nsew')
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
for i in range(100): tk.Button(main_frame.interior, text=f'test {i}').grid(row=0, column=i)
root.geometry('360x240')
root.mainloop()
The aim of the code is too have a frame that is scroll-able via both the x and y axis; however, an issue is occurring in which scrolling across the x axis results in the items not being drawn:
However, the y-axis seems to work perfectly - I have attempted to change by program with different scrollregion= settings (i.e. 'all') yet to no prevail, it seems to remove the functionality of the x-axis entirely.
You are explicitly setting the width of the interior frame to be the same as the width of the canvas. For example, when the program starts up, the canvas will be a little less than 360 pixels wide so you're setting the interior frame to be that size. On my machine that ends up being 309 pixels. Thus, when you scroll you'll only ever be able to see 309 pixels worth of buttons.
The whole point of scrolling is that you're trying to see something that is larger than the window, but you're artificially making the inner frame the same size as the window.
You should stop forcing the inner frame to be the same size as the canvas, or at least stop forcing it to be smaller than the canvas. It needs to be its natural size.
Related
I am using Python to parse entries from a log file, and display the entry contents using Tkinter and so far it's been excellent. The output is a grid of label widgets, but sometimes there are more rows than can be displayed on the screen. I'd like to add a scrollbar, which looks like it should be very easy, but I can't figure it out.
The documentation implies that only the List, Textbox, Canvas and Entry widgets support the scrollbar interface. None of these appear to be suitable for displaying a grid of widgets. It's possible to put arbitrary widgets in a Canvas widget, but you appear to have to use absolute co-ordinates, so I wouldn't be able to use the grid layout manager?
I've tried putting the widget grid into a Frame, but that doesn't seem to support the scrollbar interface, so this doesn't work:
mainframe = Frame(root, yscrollcommand=scrollbar.set)
Can anyone suggest a way round this limitation? I'd hate to have to rewrite in PyQt and increase my executable image size by so much, just to add a scrollbar!
Overview
You can only associate scrollbars with a few widgets, and the root widget and Frame aren't part of that group of widgets.
There are at least a couple of ways to do this. If you need a simple vertical or horizontal group of widgets, you can use a text widget and the window_create method to add widgets. This method is simple, but doesn't allow for a complex layout of the widgets.
A more common general-purpose solution is to create a canvas widget and associate the scrollbars with that widget. Then, into that canvas embed the frame that contains your label widgets. Determine the width/height of the frame and feed that into the canvas scrollregion option so that the scrollregion exactly matches the size of the frame.
Why put the widgets in a frame rather than directly in the canvas? A scrollbar attached to a canvas can only scroll items created with one of the create_ methods. You cannot scroll items added to a canvas with pack, place, or grid. By using a frame, you can use those methods inside the frame, and then call create_window once for the frame.
Drawing the text items directly on the canvas isn't very hard, so you might want to reconsider that approach if the frame-embedded-in-a-canvas solution seems too complex. Since you're creating a grid, the coordinates of each text item is going to be very easy to compute, especially if each row is the same height (which it probably is if you're using a single font).
For drawing directly on the canvas, just figure out the line height of the font you're using (and there are commands for that). Then, each y coordinate is row*(lineheight+spacing). The x coordinate will be a fixed number based on the widest item in each column. If you give everything a tag for the column it is in, you can adjust the x coordinate and width of all items in a column with a single command.
Object-oriented solution
Here's an example of the frame-embedded-in-canvas solution, using an object-oriented approach:
import tkinter as tk
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.canvas = tk.Canvas(self, borderwidth=0, background="#ffffff")
self.frame = tk.Frame(self.canvas, background="#ffffff")
self.vsb = tk.Scrollbar(self, orient="vertical", command=self.canvas.yview)
self.canvas.configure(yscrollcommand=self.vsb.set)
self.vsb.pack(side="right", fill="y")
self.canvas.pack(side="left", fill="both", expand=True)
self.canvas.create_window((4,4), window=self.frame, anchor="nw",
tags="self.frame")
self.frame.bind("<Configure>", self.onFrameConfigure)
self.populate()
def populate(self):
'''Put in some fake data'''
for row in range(100):
tk.Label(self.frame, text="%s" % row, width=3, borderwidth="1",
relief="solid").grid(row=row, column=0)
t="this is the second column for row %s" %row
tk.Label(self.frame, text=t).grid(row=row, column=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 = Example(root)
example.pack(side="top", fill="both", expand=True)
root.mainloop()
Procedural solution
Here is a solution that doesn't use a class:
import tkinter as tk
def populate(frame):
'''Put in some fake data'''
for row in range(100):
tk.Label(frame, text="%s" % row, width=3, borderwidth="1",
relief="solid").grid(row=row, column=0)
t="this is the second column for row %s" %row
tk.Label(frame, text=t).grid(row=row, column=1)
def onFrameConfigure(canvas):
'''Reset the scroll region to encompass the inner frame'''
canvas.configure(scrollregion=canvas.bbox("all"))
root = tk.Tk()
canvas = tk.Canvas(root, borderwidth=0, background="#ffffff")
frame = tk.Frame(canvas, background="#ffffff")
vsb = tk.Scrollbar(root, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=vsb.set)
vsb.pack(side="right", fill="y")
canvas.pack(side="left", fill="both", expand=True)
canvas.create_window((4,4), window=frame, anchor="nw")
frame.bind("<Configure>", lambda event, canvas=canvas: onFrameConfigure(canvas))
populate(frame)
root.mainloop()
Make it scrollable
Use this handy class to make the frame containing your widgets scrollable. Follow these steps:
create the frame
display it (pack, grid, etc)
make it scrollable
add widgets inside it
call the update() method
import tkinter as tk
from tkinter import ttk
class Scrollable(tk.Frame):
"""
Make a frame scrollable with scrollbar on the right.
After adding or removing widgets to the scrollable frame,
call the update() method to refresh the scrollable area.
"""
def __init__(self, frame, width=16):
scrollbar = tk.Scrollbar(frame, width=width)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y, expand=False)
self.canvas = tk.Canvas(frame, yscrollcommand=scrollbar.set)
self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
scrollbar.config(command=self.canvas.yview)
self.canvas.bind('<Configure>', self.__fill_canvas)
# base class initialization
tk.Frame.__init__(self, frame)
# assign this obj (the inner frame) to the windows item of the canvas
self.windows_item = self.canvas.create_window(0,0, window=self, anchor=tk.NW)
def __fill_canvas(self, event):
"Enlarge the windows item to the canvas width"
canvas_width = event.width
self.canvas.itemconfig(self.windows_item, width = canvas_width)
def update(self):
"Update the canvas and the scrollregion"
self.update_idletasks()
self.canvas.config(scrollregion=self.canvas.bbox(self.windows_item))
Usage example
root = tk.Tk()
header = ttk.Frame(root)
body = ttk.Frame(root)
footer = ttk.Frame(root)
header.pack()
body.pack()
footer.pack()
ttk.Label(header, text="The header").pack()
ttk.Label(footer, text="The Footer").pack()
scrollable_body = Scrollable(body, width=32)
for i in range(30):
ttk.Button(scrollable_body, text="I'm a button in the scrollable frame").grid()
scrollable_body.update()
root.mainloop()
Extends class tk.Frame to support a scrollable Frame
This class is independent from the widgets to be scrolled and can be used to replace a standard tk.Frame.
import tkinter as tk
class ScrollbarFrame(tk.Frame):
"""
Extends class tk.Frame to support a scrollable Frame
This class is independent from the widgets to be scrolled and
can be used to replace a standard tk.Frame
"""
def __init__(self, parent, **kwargs):
tk.Frame.__init__(self, parent, **kwargs)
# The Scrollbar, layout to the right
vsb = tk.Scrollbar(self, orient="vertical")
vsb.pack(side="right", fill="y")
# The Canvas which supports the Scrollbar Interface, layout to the left
self.canvas = tk.Canvas(self, borderwidth=0, background="#ffffff")
self.canvas.pack(side="left", fill="both", expand=True)
# Bind the Scrollbar to the self.canvas Scrollbar Interface
self.canvas.configure(yscrollcommand=vsb.set)
vsb.configure(command=self.canvas.yview)
# The Frame to be scrolled, layout into the canvas
# All widgets to be scrolled have to use this Frame as parent
self.scrolled_frame = tk.Frame(self.canvas, background=self.canvas.cget('bg'))
self.canvas.create_window((4, 4), window=self.scrolled_frame, anchor="nw")
# Configures the scrollregion of the Canvas dynamically
self.scrolled_frame.bind("<Configure>", self.on_configure)
def on_configure(self, event):
"""Set the scroll region to encompass the scrolled frame"""
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
Usage:
class App(tk.Tk):
def __init__(self):
super().__init__()
sbf = ScrollbarFrame(self)
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
sbf.grid(row=0, column=0, sticky='nsew')
# sbf.pack(side="top", fill="both", expand=True)
# Some data, layout into the sbf.scrolled_frame
frame = sbf.scrolled_frame
for row in range(50):
text = "%s" % row
tk.Label(frame, text=text,
width=3, borderwidth="1", relief="solid") \
.grid(row=row, column=0)
text = "this is the second column for row %s" % row
tk.Label(frame, text=text,
background=sbf.scrolled_frame.cget('bg')) \
.grid(row=row, column=1)
if __name__ == "__main__":
App().mainloop()
I am trying to write a application where i will get the size of the screen and then resize GUI to take full screen accordingly.
Also, i have 3 frames inside that application. The three frames will have separate widgets. Now based on the screen size available i would like to change the layout of the widgets a bit and also the size of text and wrap length of the texts.
I understood that frame will not have proper size until it have a widget, so i am adding dummy canvas widget. But then also the width of the frames are not getting proper. Am i not doing the thing properly ? If you run the below code frame 1 and frame 2 are having same widths even though visually they are not at all same.
import tkinter as tk
from win32api import GetSystemMetrics
class MainApplication:
def __init__(self):
self.root = tk.Tk()
self.width = GetSystemMetrics(0)
self.height = GetSystemMetrics(1)
self.root.geometry('{}x{}'.format(self.width, self.height))
frame1 = tk.Frame(self.root,bg='blue')
frame1.grid(row=0, column=0, sticky="nsew",rowspan=2)
self.root.grid_columnconfigure(0, weight=5000)
frame1.grid_rowconfigure(0,weight=1)
frame1.grid_columnconfigure(0,weight=1)
self.canvas = tk.Canvas(frame1,bg='blue')
self.canvas.grid(row=0, column=0, sticky="nsew")
self.canvas.update()
print(frame1.winfo_reqwidth())
self.frame2 = tk.Frame(self.root,bg='red')
self.root.grid_columnconfigure(1, weight=1)
self.frame2.grid(row=0, column=1, sticky="nsew")
self.frame2.grid_rowconfigure(0, weight=1)
self.frame2.grid_columnconfigure(0, weight=1)
self.canvas1 = tk.Canvas(self.frame2,bg='red')
self.canvas1.grid(row=0, column=0, sticky="nsew")
self.canvas1.update()
print(self.frame2.winfo_reqwidth())
self.frame3 = tk.Frame(self.root, bg='green')
self.frame3.grid(row=1,column=1,sticky="nsew")
self.root.grid_rowconfigure(1,weight=5000)
self.frame3.grid_rowconfigure(0, weight=1)
self.frame3.grid_columnconfigure(0, weight=1)
self.canvas2 = tk.Canvas(self.frame3,bg='green')
self.canvas2.grid(row=0, column=0, sticky="nsew")
self.canvas2.update()
self.root.mainloop()
if __name__ == '__main__':
a = MainApplication()
I tried many things to do 2 things :
center my content (horizontal)
have a scrollbar right and bottom
Here my code :
# encoding: utf8
from tkinter import *
from tkinter import ttk
class Program:
def __init__(self):
# Tk.__init__(self)
# Fill the content of the window
self.window = Tk()
self.window.geometry("1080x720")
self.createFrameWithScrollbar()
self.content()
def createFrameWithScrollbar(self):
# Create a Main Frame
self.mainFrame = Frame(self.window)
self.mainFrame.pack(fill=BOTH, expand=True)
# Create a canvas
self.canvas = Canvas(self.mainFrame)
self.canvas.pack(side=LEFT, fill=BOTH, expand=True)
# Add a scrobar
yScrollbar = ttk.Scrollbar(self.mainFrame, orient=VERTICAL, command=self.canvas.yview)
yScrollbar.pack(side=RIGHT, fill=Y)
xScrollbar = ttk.Scrollbar(self.mainFrame, orient=HORIZONTAL, command=self.canvas.xview)
xScrollbar.pack(side=BOTTOM, fill=X)
# Configure the canvas
self.canvas.configure(yscrollcommand=yScrollbar.set)
self.canvas.configure(xscrollcommand=xScrollbar.set)
self.canvas.bind('<Configure>', lambda e: self.canvas.configure(scrollregion = self.canvas.bbox("all")))
self.frame = Frame(self.canvas)
self.canvas.create_window((0,0), window=self.frame, anchor="nw")
self.currentFrame = Frame(self.frame)
self.currentFrame.configure(bg="red")
self.currentFrame.pack(fill=BOTH, expand=1)
def content(self):
label_title = Label(self.currentFrame, text="Title")
label_title.grid(column=0, row=0, sticky=NSEW)
label_description = Label(self.currentFrame, text="Title")
label_description.grid(column=0, row=1, sticky=NSEW)
label_version = Label(self.currentFrame, text="0.2 beta [Novembre 2020]")
label_version.grid(column=0, row=2, sticky=NSEW)
# Lauch the program
app = Program()
app.window.mainloop()
So the result is the following :
So any suggestion ?
The bottom sidebar is so small ! I don't know why.
Are regarding the text, it's not center at all ;(
I want to have it center and changing position if I rezize the window
Thanks a lot
pack works by allocating space along an entire empty side of the master, so the order of when you call pack matters. When you pack the canvas before packing the scrollbar, the canvas takes up the entire left side from top to bottom.
The simple solution is to pack the scrollbars before you pack the canvas.
yScrollbar.pack(side=RIGHT, fill=Y)
xScrollbar.pack(side=BOTTOM, fill=X)
self.canvas.pack(side=LEFT, fill=BOTH, expand=True)
To make the UI look a bit more professional, grid is usually a better choice when laying out scrollbars. With pack, either one edge of the horizontal scrollbar will be below the vertical scrollbar, or the edge of the vertical scrollbar will be directly beside the horizontal one. That, or you have to add a little bit of padding so the scrollbars don't seem to overlap.
When I have a scrollable widget, I almost always put it and the one or two scrollbars together in a frame using grid. Then, I can treat them all as if they were a single widget when adding them to the rest of the UI.
In a comment you ask about how to do it in a grid. You simply need to place the widgets in the appropriate rows and columns, and make sure that the row and column with the scrollable widget has a non-zero weight so any extra space is allocated to it.
self.mainFrame.grid_rowconfigure(0, weight=1)
self.mainFrame.grid_columnconfigure(0, weight=1)
yScrollbar.grid(row=0, column=1, sticky="ns")
xScrollbar.grid(row=1, column=0, sticky="ew")
self.canvas.grid(row=0, column=0, sticky="nsew")
I'm trying to do a scrollable application with two buttons. Pressing one of those buttons should be put a new button in the Frame, and scroll the widgets inside the frame.
My question is how to put the two buttons in the frame?
when I try to put in the same Frame only I can see one button and only a small part of the other.
How to solve this?
from tkinter import * # from x import * is bad practice
global y
y=0
def _configure_interior(event):
print("hola")
size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
canvas.config(scrollregion="0 0 %s %s" % size)
def newbutton():
buttons=Button(interior, text="Button ")
buttons.pack()
#b2.place(y=50)
root =Tk()
#configuring the Scrollbars
vscrollbar = Scrollbar(root, orient=VERTICAL)
vscrollbar.pack(fill=Y, side=RIGHT)
hscrollbar = Scrollbar(root, orient=HORIZONTAL)
hscrollbar.pack(fill=X, side=BOTTOM)
#setting canvas with scrollbar
canvas = Canvas(root,height=500, width=500, bg="blue",
yscrollcommand=vscrollbar.set,xscrollcommand=hscrollbar.set)
canvas.propagate(0)
vscrollbar.config(command=canvas.yview)
hscrollbar.config(command=canvas.xview)
canvas.pack()
#making a interior scrolleable frame
interior = Frame(canvas,bg='black',height=600,width=600)
interior.pack(side="top", fill="both", expand=True)
#adding some widgets to the Frame
b=Button(interior, text="Button 2",command=newbutton)
b.pack()
b2=Button(interior, text="Button 2",command=newbutton)
b2.pack()
b2.place(x=50,y=50)
interior_id = canvas.create_window(30,30, window=interior,
anchor=NW)
interior.bind('<Configure>', _configure_interior)
root.mainloop()
You have also used pack() to place the interior frame on the canvas, which does not work. I've commentet that line out in the code below. Also I've commented out the b2.place() as you should not use more tham one geometry manager in a frame.
#making a interior scrolleable frame
interior = Frame(canvas,bg='black',height=600,width=600)
#interior.pack(side="top", fill="both", expand=True)
interior_id = canvas.create_window(30,30, window=interior,
anchor=NW)
#adding some widgets to the Frame
b=Button(interior, text="Button 2",command=newbutton)
b.pack()
b2=Button(interior, text="Button 2",command=newbutton)
b2.pack()
#b2.place(x=50,y=50)
The new buttons are now packed into interior.
I would like to have my scrollbar in the bottom of the frame and my text widgets filling the whole frame above the scrollbar. I found some solution about the width configuration here but when I try to replace width with height, it does not work correctly.
from tkinter import *
from tkinter import ttk
class MainView(Frame):
def FrameHeight(self, event):
canvas_height = event.height
self.canvas.itemconfig(self.canvas_frame, height=canvas_height)
def OnFrameConfigure(self, event):
self.canvas.config(scrollregion=self.canvas.bbox("all"))
def __init__(self, *args, **kwargs):
Frame.__init__(self, *args, **kwargs)
self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure(0, weight=1)
sensorsFrame = Frame(self)
sensorsFrame.grid(row=0, sticky="nsew")
sensorsFrame.grid_columnconfigure(0, weight=1)
sensorsFrame.grid_rowconfigure(0, weight=1)
self.canvas = Canvas(sensorsFrame)
self.sensorsStatsFrame = Frame(self.canvas)
self.canvas.grid_rowconfigure(0, weight=1)
self.sensorsStatsFrame.grid_rowconfigure(0, weight=1)
myscrollbar = Scrollbar(sensorsFrame,orient=HORIZONTAL,command=self.canvas.xview)
self.canvas.configure(xscrollcommand=myscrollbar.set)
self.canvas.pack(fill=BOTH, expand=1)
myscrollbar.pack(fill=X, expand=1)
test0 = Text(self.sensorsStatsFrame, state=DISABLED)
test1 = Text(self.sensorsStatsFrame, width=150)
test0.grid(column=0, row=0, sticky="nsew")
test1.grid(column=1, row=0, sticky="nsew")
self.canvas_frame = self.canvas.create_window((0,0),window=self.sensorsStatsFrame,anchor='nw')
self.sensorsStatsFrame.bind("<Configure>", self.OnFrameConfigure)
#When I try to use what i found
#self.canvas.bind('<Configure>', self.FrameHeight)
if __name__ == "__main__":
root = Tk()
main = MainView(root)
main.pack(fill="both", expand=1)
root.wm_geometry("1100x500")
root.wm_title("MongoDB Timed Sample Generator")
root.mainloop()
Step 1: Remove space above and below the scrollbar
The expand option determines how tkinter handles unallocated space. Extra space will be evenly allocated to all widgets where the value is 1 or True. Because it's set to 1 for the scrollbar, it is given some of the extra space, causing the padding above and below the widget.
What you want instead is for all of the space to be allocated only to the canvas. Do this by setting expand to zero on the scrollbar:
myscrollbar.pack(fill=X, expand=0)
Step 2: call a function when the canvas changes size
The next problem is that you want the inner frame to grow when the canvas changes size, so you need to bind to the <Configure> event of the canvas.
def OnCanvasConfigure(self, event):
<code to set the size of the inner frame>
...
self.canvas.bind("<Configure>", self.OnCanvasConfigure)
Step 3: let the canvas control the size of the inner frame
You can't just change the size of the inner frame in OnCanvasConfigure, because the default behavior of a frame is to shrink to fit its contents. In this case you want the contents to expand to fit the frame rather than the frame shrink to fit the contents.
There are a couple ways you can fix this. You can turn geometry propagation off for the inner frame, which will prevent the inner widgets from changing the size of the frame. Or, you can let the canvas force the size of the frame.
The second solution is the easiest. All we have to do is use the height of the canvas for the frame height, and the sum of the widths of the inner text widgets for the frame width.
def OnCanvasConfigure(self, event):
width = 0
for child in self.sensorsStatsFrame.grid_slaves():
width += child.winfo_reqwidth()
self.canvas.itemconfigure(self.canvas_frame, width=width, height=event.height)
Step 4: fix the scrollbar
There's still one more problem to solve. If you resize the window you'll notice that tkinter will chop off the scrollbar if the window gets too small. You can solve this by removing the ability to resize the window but your users will hate that.
A better solution is to cause the text widgets to shrink before the scrollbar is chopped off. You control this by the order in which you call pack.
When there isn't enough room to fit all of the widgets, tkinter will start reducing the size of widgets, starting with the last widget added to the window. In your code the scrollbar is the last widget, but if instead you make it the canvas, the scrollbar will remain untouched and the canvas will shrink instead (which in turn causes the frame to shrink, which causes the text widgets to shrink).
myscrollbar.pack(side="bottom", fill=X, expand=0)
self.canvas.pack(fill=BOTH, expand=1)
Changing pack layout to grid layout for self.canvas and myscrollbar makes it work.
from tkinter import *
from tkinter import ttk
class MainView(Frame):
def FrameHeight(self, event):
canvas_height = event.height
self.canvas.itemconfig(self.canvas_frame, height = canvas_height)
def OnFrameConfigure(self, event):
self.canvas.config(scrollregion=self.canvas.bbox("all"))
def __init__(self, *args, **kwargs):
Frame.__init__(self, *args, **kwargs)
self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure(0, weight=1)
sensorsFrame = Frame(self)
sensorsFrame.grid(row=0, sticky="nsew")
sensorsFrame.grid_rowconfigure(0, weight=1)
sensorsFrame.grid_columnconfigure(0, weight=1)
self.canvas = Canvas(sensorsFrame, bg="blue")
self.sensorsStatsFrame = Frame(self.canvas)
self.canvas.grid_rowconfigure(0, weight=1)
self.sensorsStatsFrame.grid_rowconfigure(0, weight=1)
myscrollbar = Scrollbar(sensorsFrame,orient=HORIZONTAL,command=self.canvas.xview)
self.canvas.configure(xscrollcommand=myscrollbar.set)
self.canvas.grid(row=0, sticky="nsew")
myscrollbar.grid(row=1, sticky="nsew")
test0 = Text(self.sensorsStatsFrame, state=DISABLED, bg="red")
test1 = Text(self.sensorsStatsFrame, width=150)
test0.grid(column=0, row=0, sticky="nsew")
test1.grid(column=1, row=0, sticky="nsew")
self.canvas_frame = self.canvas.create_window((0,0),window=self.sensorsStatsFrame,anchor='nw')
self.sensorsStatsFrame.bind("<Configure>", self.OnFrameConfigure)
self.canvas.bind('<Configure>', self.FrameHeight)
if __name__ == "__main__":
root = Tk()
main = MainView(root)
main.pack(fill="both", expand=1)
root.wm_geometry("1100x500")
root.wm_title("MongoDB Timed Sample Generator")
root.mainloop()