Lona desplazable de tamaño variable con tkinter

Aquí mi código para una gui muy simple:

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() 

Tengo dos preguntas:

1) Quiero que si cambio el tamaño de la interfaz gráfica de usuario, que las barras de desplazamiento estén siempre en los extremos de la interfaz gráfica de usuario y que cambie el tamaño del canvas.

2) Si cambio el tamaño de la GUI y el canvas, entonces el rectángulo en el canvas se cambiará de tamaño (por ejemplo, si el nuevo tamaño de gui y canvas es cuatro veces el tamaño anterior, entonces el nuevo tamaño del rectángulo es el tamaño anterior) .

Busco una solución para el primer problema y para el segundo problema por separado.

Gracias por la ayuda.

Podría usar la siguiente forma de integrar mi marco en su clase de GUI:

 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_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() 

Esto esencialmente debería resolver su primer problema. En cuanto al segundo problema, deberá crear una función para volver a renderizar el canvas cada vez que lo cambie de tamaño. De una manera similar a la función _configure_interior.

Podría usar este ejemplo siguiente, o integrarlo en su clase. Podrías crear un marco como este llamando.

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

Crea una clase como esta para tu marco:

 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_interior) 

Podría usar esto para obtener el resultado que desea. Tanto el desplazamiento horizontal como el vertical están habilitados para este cuadro y las posiciones de la barra de desplazamiento se pueden configurar usando el campo ‘lateral’. Para la segunda parte de tu pregunta, ¿podrías aclarar más?

Referencia: la respuesta de Gonzo Python Tkinter scrollbar for frame

Esto funciona muy bien, para obtener lo que quiero con el tamaño de canvas desplazable mínimo. Pero todavía existe el error, cuando el gui se hizo más grande y cuando parece que no se puede desplazar, existe la posibilidad de hacer clic en la flecha superior o izquierda de las barras de desplazamiento y, por lo tanto, desplazarse por el canvas, ¿qué debería hacer? no será posible

 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_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()