I have written an application that allows users to select a directory and load the info in the directory. The user can then select which aspects of the files to display in a figure. The figure is placed in a Tkinter-matplotlib canvas which is within a canvas window that the user can scroll. The issue I am having is that the frame (canvas_frame in StartPage) containing the scrollable frame doesn't take the allotted space in the Tkinter window.
The code below replicates the issue and the the image is what the application looks like. Most of the code for the scrollable frame was taken from ex. 1 and ex. 2. An image of the application is here:
https://i.stack.imgur.com/jle7H.jpg
from tkinter import Tk, Frame, Canvas
from tkinter.ttk import Scrollbar
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg as FigCanvas
from matplotlib.figure import Figure
class Scrollable(Frame):
def __init__(self, frame, fig, width=16):
# Base class initialization
Frame.__init__(self, frame)
# Instance variable for tkinter canvas
self.tk_cnv = Canvas(frame, highlightthickness=0)
self.tk_cnv.pack(side='left', fill='both', expand=True)
# Instance variable for the scroll-bar
v_scroll = Scrollbar(frame, width=width)
v_scroll.pack(side="right", fill="y", expand=False)
v_scroll.config(command=self.tk_cnv.yview)
v_scroll.activate(" ")
# Instance variable for the matplotlib canvas
self.mpl_cnv = FigCanvas(fig, frame)
self.cnv_widget = self.mpl_cnv.get_tk_widget()
self.cnv_widget.config(yscrollcommand=v_scroll.set)
self.cnv_widget.bind("<Configure>", self.__fill_canvas)
# Assign frame generated by the class to the canvas
# and create a scrollable window for it.
self.windows_item = \
self.tk_cnv.create_window((0, 900), window=self.cnv_widget, anchor='e',
tag='self.canvas')
self.tk_cnv.config(scrollregion=self.tk_cnv.bbox("all"))
def __fill_canvas(self, event):
# Enlarge the windows item to the canvas width
canvas_width = event.width
canvas_height = event.height
self.tk_cnv.itemconfig(self.windows_item, width=canvas_width,
height=canvas_height)
class StartPage(Frame):
""" Tkinter based class for single frame upon which widgets
such as buttons, check-buttons, and entry are used as a
simple graphical user interface.
"""
LARGE_FONT = ("Veranda", 12)
def __init__(self, parent, controller):
Frame.__init__(self, parent)
# Instance variables with page/window info of current frame
self.window = parent
# Instance variable for third row of widgets
self.canvas_frame = Frame(self.window, relief="sunken")
self.canvas_frame.grid(row=0, column=0, pady=5, sticky="news")
# Instance variables for the figure
self.plot_fig = Figure(figsize=[14.0, 18.0])
# Instance variable for the frame with scrolling functionality
self.canvas_body = Scrollable(self.canvas_frame, self.plot_fig)
self.canvas = self.canvas_body.mpl_cnv
self.canvas_setup()
def canvas_setup(self):
self.canvas_frame.grid_rowconfigure(2, weight=1)
self.canvas_frame.grid_columnconfigure(0, weight=1)
class MainContainer(Tk):
""" Tkinter based class used to generate a single window
and contain a single frame. The frame contains multiple
widgets for user choice and visualization.
"""
def __init__(self, *args, **kwargs):
Tk.__init__(self, *args, **kwargs)
Tk.wm_title(self, "Sequence Viewer")
Tk.wm_resizable(self, width=True, height=True)
container = Frame(self)
container.grid_configure(row=0, column=0, sticky="nsew")
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
frame = StartPage(container, self)
self.frames[StartPage] = frame
self.show_frame(StartPage)
self.center_window()
def show_frame(self, frame_to_add):
frame = self.frames[frame_to_add]
frame.tkraise()
def center_window(self):
w = 1100
h = 900
sw = self.winfo_screenwidth()
sh = self.winfo_screenheight()
x = (sw - w) / 2
y = (sh - h) / 2
self.geometry('%dx%d+%d+%d' % (w, h, x, y))
if __name__ == "__main__":
app = MainContainer()
app.mainloop()