3

Here my code for a very simple gui:

from Tkinter import * class my_gui(Frame): def __init__(self): # main tk object self.root = Tk() # init Frame Frame.__init__(self, self.root) # create frame (gray window) self.frame=Frame(self.root,width=100,height=100) self.frame.grid(row=0,column=0) self.__add_scroll_bars() self.__create_canvas() self.__add_plot() def __create_canvas(self): # create white area in the window for plotting # width and height are only the visible size of the white area, scrollregion is the area the user can see by scrolling self.canvas = Canvas(self.frame,bg='#FFFFFF',width=300,height=300,scrollregion=(0,0,500,500)) # with this command the window is filled with the canvas self.canvas.pack(side=LEFT,expand=True,fill=BOTH) # position and size of the canvas is used for configuration of the scroll bars self.canvas.config(xscrollcommand=self.hbar.set, yscrollcommand=self.vbar.set) # add command to the scroll bars to scroll the canvas self.hbar.config(command = self.canvas.xview) self.vbar.config(command = self.canvas.yview) def __add_scroll_bars(self): # add scroll bars self.hbar=Scrollbar(self.frame,orient=HORIZONTAL) self.hbar.pack(side=BOTTOM,fill=X) self.vbar=Scrollbar(self.frame,orient=VERTICAL) self.vbar.pack(side=RIGHT,fill=Y) def __add_plot(self): # create a rectangle self.canvas.create_polygon(10, 10, 10, 150, 200, 150, 200, 10, fill="gray", outline="black") def mainLoop(self): # This function starts an endlos running thread through the gui self.root.mainloop() def __quit(self): # close everything self.root.quit() def mainLoop(self): # This function starts an endlos running thread through the gui self.root.mainloop() # init gui my_gui = my_gui() # execute gui my_gui.mainLoop() 

I have two questions:

1) I want if I resize the gui, that then the scrollbars are always on the Ends of the gui and I resize the canvas.

2) If I resize the GUI and the canvas, then the rectangle in the canvas shall be resized (for example if the new size of gui and canvas is four times the old size, then the new size of rectangle is twize the old size).

I search a solution for the first problem and for the second problem seperately.

Thanks for help.

3 Answers 3

1

You could use the following way to integrate my frame into your gui class:

from Tkinter import * class ScrollableFrame(Frame): def __init__(self, parent, *args, **kw): ''' Constructor ''' Frame.__init__(self, parent, *args, **kw) # create a vertical scrollbar vscrollbar = Scrollbar(self, orient = VERTICAL) vscrollbar.pack(fill = Y, side = RIGHT, expand = FALSE) # create a horizontal scrollbar hscrollbar = Scrollbar(self, orient = HORIZONTAL) hscrollbar.pack(fill = X, side = BOTTOM, expand = FALSE) #Create a canvas object and associate the scrollbars with it self.canvas = Canvas(self, bd = 0, highlightthickness = 0, yscrollcommand = vscrollbar.set, xscrollcommand = hscrollbar.set) self.canvas.pack(side = LEFT, fill = BOTH, expand = TRUE) #Associate scrollbars with canvas view vscrollbar.config(command = self.canvas.yview) hscrollbar.config(command = self.canvas.xview) # set the view to 0,0 at initialization self.canvas.xview_moveto(0) self.canvas.yview_moveto(0) # create an interior frame to be created inside the canvas self.interior = interior = Frame(self.canvas) interior_id = self.canvas.create_window(0, 0, window=interior, anchor=NW) # track changes to the canvas and frame width and sync them, # also updating the scrollbar def _configure_interior(event): # update the scrollbars to match the size of the inner frame size = (interior.winfo_reqwidth(), interior.winfo_reqheight()) self.canvas.config(scrollregion='0 0 %s %s' % size) if interior.winfo_reqwidth() != self.canvas.winfo_width(): # update the canvas's width to fit the inner frame self.canvas.config(width = interior.winfo_reqwidth()) interior.bind('<Configure>', _configure_interior) class my_gui(Frame): def __init__(self): # main tk object self.root = Tk() # init Frame Frame.__init__(self, self.root) # create frame (gray window) self.frame = ScrollableFrame(self.root) self.frame.pack(fill=BOTH, expand=YES) #self.__add_scroll_bars() #self.__create_canvas() self.__add_plot() def __add_plot(self): # create a rectangle self.frame.canvas.create_polygon(10, 10, 10, 150, 200, 150, 200, 10, fill="gray", outline="black") def mainLoop(self): # This function starts an endlos running thread through the gui self.root.mainloop() def __quit(self): # close everything self.root.quit() # init gui my_gui = my_gui() # execute gui my_gui.mainLoop() 

This should essentially solve your first problem. As for the second problem you'll need to create a function to re-render the canvas every time you resize it. In a way similar to the _configure_interior function.

Sign up to request clarification or add additional context in comments.

3 Comments

Hallo, for the first it works, but in this example the scrollbars makes no sense, there is nothing to scroll, the canvas has always exact the same size as the scrollbars, I can never scroll. I wanted to scroll when the GUI is small enough (maybe when the gui is smaller than 500 times 500, then I want to scroll this size.. For the second when you make the gui larger, the scroll bar seems so, that you can not scroll. But when you click on the left arrow of the bottom scroll bar, then you can see, that the rectangle moves to the right. Is this a bug?
In some cases it works to replace the line "size = (interior.winfo_reqwidth(), interior.winfo_reqheight())" by "size = ( max( 500, interior.winfo_reqwidth() ), max( 500, interior.winfo_reqheight() ) ) " to get in the most cases a scrollable canvas of size 500 times 500 at minimum. But the _configure_interior function seems not to be called in each case, when the size of the gui was changed.
I did not encounter the bug when I executed it. As for the scrollbars not making sense, that is because you just have a plain canvas with a polygon in it. You could pack in other elements (like labels, checkboxes, buttons etc) to see that the scrollbars would be activated once the window size is lesser than the required size to display all elements.
0

You could use this following example, or integrate it in your class. You could create a frame like this by calling.

self.frame = ScrollableFrame(self.root) self.frame.pack(fill=BOTH, expand=YES) 

Create a class like this for your frame:

from Tkinter import * class ScrollableFrame(Frame): ''' Creates a scrollable frame ''' def __init__(self, parent, *args, **kw): ''' Constructor ''' Frame.__init__(self, parent, *args, **kw) # create a vertical scrollbar vscrollbar = Scrollbar(self, orient = VERTICAL) vscrollbar.pack(fill = Y, side = RIGHT, expand = FALSE) # create a horizontal scrollbar hscrollbar = Scrollbar(self, orient = HORIZONTAL) hscrollbar.pack(fill = X, side = BOTTOM, expand = FALSE) #Create a canvas object and associate the scrollbars with it canvas = Canvas(self, bd = 0, highlightthickness = 0, yscrollcommand = vscrollbar.set, xscrollcommand = hscrollbar.set) canvas.pack(side = LEFT, fill = BOTH, expand = TRUE) #Associate scrollbars with canvas view vscrollbar.config(command = canvas.yview) hscrollbar.config(command = canvas.xview) # set the view to 0,0 at initialization canvas.xview_moveto(0) canvas.yview_moveto(0) # create an interior frame to be created inside the canvas self.interior = interior = Frame(canvas) interior_id = canvas.create_window(0, 0, window=interior, anchor=NW) # track changes to the canvas and frame width and sync them, # also updating the scrollbar def _configure_interior(event): # update the scrollbars to match the size of the inner frame size = (interior.winfo_reqwidth(), interior.winfo_reqheight()) canvas.config(scrollregion='0 0 %s %s' % size) if interior.winfo_reqwidth() != canvas.winfo_width(): # update the canvas's width to fit the inner frame canvas.config(width = interior.winfo_reqwidth()) interior.bind('<Configure>', _configure_interior) 

You could use this to obtain the result you want. Horizontal and Vertical scrolling are both enabled for this frame and scrollbar positions can be set using 'side' field. For the second part of your question, could you elucidate further.

Reference: Gonzo's answer Python Tkinter scrollbar for frame

2 Comments

Do you have a simple example, where this class ScrollableFrame is used with a canvas inside for example? I don't really understand how I can integrate this class in my example. I see, that a lot of code is the same like the Scrollbars and I see, that the trick for resizeable Scrollbars seems to be the _configure_interior function and the create_window function, but I don't really understand why.
This example makes a canvas with horizontal and vertical scrollbars, but from what I can tell no slider ever appears, even when the size of the frame exceeds the size of the canvas it is placed on. pastebin.com/J7d0ChzX
0

This works very well, to get what I want with the minimal scrollable canvas size. But there is still the bug, when the gui was made larger and when it seems so, that one can not scroll, there is the possibility to click on the left or upper arrow of the scroll bars and so to scroll the canvas, what sould not be possible.

from Tkinter import * class ScrollableFrame(Frame): def __init__(self, parent, minimal_canvas_size, *args, **kw): ''' Constructor ''' Frame.__init__(self, parent, *args, **kw) self.minimal_canvas_size = minimal_canvas_size # create a vertical scrollbar vscrollbar = Scrollbar(self, orient = VERTICAL) vscrollbar.pack(fill = Y, side = RIGHT, expand = FALSE) # create a horizontal scrollbar hscrollbar = Scrollbar(self, orient = HORIZONTAL) hscrollbar.pack(fill = X, side = BOTTOM, expand = FALSE) #Create a canvas object and associate the scrollbars with it self.canvas = Canvas(self, bd = 0, highlightthickness = 0, yscrollcommand = vscrollbar.set, xscrollcommand = hscrollbar.set) self.canvas.pack(side = LEFT, fill = BOTH, expand = TRUE) #Associate scrollbars with canvas view vscrollbar.config(command = self.canvas.yview) hscrollbar.config(command = self.canvas.xview) # set the view to 0,0 at initialization self.canvas.xview_moveto(0) self.canvas.yview_moveto(0) self.canvas.config(scrollregion='0 0 %s %s' % self.minimal_canvas_size) # create an interior frame to be created inside the canvas self.interior = interior = Frame(self.canvas) interior_id = self.canvas.create_window(0, 0, window=interior, anchor=NW) # track changes to the canvas and frame width and sync them, # also updating the scrollbar def _configure_interior(event): # update the scrollbars to match the size of the inner frame size = (max(interior.winfo_reqwidth(), self.minimal_canvas_size[0]), max(interior.winfo_reqheight(), self.minimal_canvas_size[1])) self.canvas.config(scrollregion='0 0 %s %s' % size) if interior.winfo_reqwidth() != self.canvas.winfo_width(): # update the canvas's width to fit the inner frame self.canvas.config(width = interior.winfo_reqwidth()) interior.bind('<Configure>', _configure_interior) class my_gui(Frame): def __init__(self): # main tk object self.root = Tk() # init Frame Frame.__init__(self, self.root) minimal_canvas_size = (500, 500) # create frame (gray window) self.frame = ScrollableFrame(self.root, minimal_canvas_size) self.frame.pack(fill=BOTH, expand=YES) self.__add_plot() def __add_plot(self): # create a rectangle self.frame.canvas.create_polygon(10, 10, 10, 150, 200, 150, 200, 10, fill="gray", outline="black") def mainLoop(self): # This function starts an endlos running thread through the gui self.root.mainloop() def __quit(self): # close everything self.root.quit() # init gui my_gui = my_gui() # execute gui my_gui.mainLoop() 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.