Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get FigureCanvasTkAgg to work with Scrollbar

I want to plot inside a tkinter application. In the final program there will be many subplots arranged vertically, more than fit on the screen. So I want to have a reasonably sized window with a scrollbar to scroll down.

Starting from an example with Canvas found here Tkinter Scrollbar Patterns I created this minimal example of my struggling:

#!/usr/bin/python

from Tkinter import Tk, Frame, Canvas, Scrollbar, HORIZONTAL, VERTICAL, BOTH, X, Y, BOTTOM, RIGHT, LEFT, S, N, W, E
from numpy import arange, sin
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

class Test(Tk):
    def __init__(self):
        Tk.__init__(self, None)
        self.frame=Frame(None)
        self.frame.columnconfigure(0,weight=1)
        self.frame.rowconfigure(0,weight=1)

        self.frame.grid(row=0,column=0, sticky=W+E+N+S)

        fig = Figure()

        xval = arange(200)/10.
        yval = sin(xval)

        ax1 = fig.add_subplot(111)
        ax1.plot(xval, yval)

        self.hbar=Scrollbar(self.frame,orient=HORIZONTAL)
        self.vbar=Scrollbar(self.frame,orient=VERTICAL)

        self.canvas=FigureCanvasTkAgg(fig, master=self.frame)
        self.canvas.get_tk_widget().config(bg='#FFFFFF',scrollregion=(0,0,500,500))
        self.canvas.get_tk_widget().config(width=300,height=300)
        self.canvas.get_tk_widget().config(xscrollcommand=self.hbar.set, yscrollcommand=self.vbar.set)
        self.canvas.get_tk_widget().grid(row=0, column=0, sticky=W+E+N+S)

        self.hbar.grid(row=1, column=0, sticky=W+E)
        self.hbar.config(command=self.canvas.get_tk_widget().xview)
        self.vbar.grid(row=0, column=1, sticky=N+S)
        self.vbar.config(command=self.canvas.get_tk_widget().yview)

        self.frame.config(width=100, height=100) # this has no effect

if __name__ == '__main__':

    app = Test()
    app.mainloop()

Here are my main 2 problems:

  1. When I resize the window, the scrollbar is static, i.e. if I decrease the window size with the mouse drag, it dissappears with the rest of the plot
  2. More importantly: if I increase the canvas size in the code, the window size is also increased. I tried adding a self.canvas.get_tk_widget().grid_propagate(0) without success...

I need the window size to be smaller than the plot size at the beginning.

like image 220
steffen Avatar asked Oct 26 '25 03:10

steffen


1 Answers

Solution:

if __name__ == '__main__':

    app = Test()
    app.rowconfigure( 0, weight=1 )     # You need to add this. 
    app.columnconfigure( 0, weight=1 )  # You need to add this.

    app.mainloop()

Your Tk window has a child tk.Frame widget, i.e. Tk.frame, located at the Tk window's (0,0) grid position. The size of Tk.frame by default will be the size of it's child widget(s), which presently is a matplotlib backend FigureCanvasTkAgg object that has a tk.Canvas widget, i.e. Tk.frame.canvas.get_tk_widget(), which you have set to be 300x300 pixels wide and high.

You need these additional two lines to instruct the Tk window's grid cell (0,0) to be stretchable. That is, cell (0,0) border should stretch to "touch the Tk window's border at all times". This action ensures the size of Tk.frame is always the size of the Tk window.

Presently, when you resize the Tk window without the added lines, you are seeing the Tk window resizing with the size of Tk.frame remaining constant at 300x300 pixels wide and high.

like image 66
Sun Bear Avatar answered Oct 28 '25 19:10

Sun Bear