Apr-14-2017, 08:02 PM
Hi weatherman
Python programmers try to follow a certain styleguide by writing a script. If you have time, I would take a look at it. Contact the following link:
PEP 8 -- Style Guide for Python Code
https://www.python.org/dev/peps/pep-0008/
So my style differs from yours
weatherman wuf
--------------------------------------------
self._customGUI self.app_win
self._buttonFrame self.button_frame
self._buttonCanvas self.button_canvas
--------------------------------------------
The following script changes the size of the 'button_frame' depending on the change of the main window 'app_win'. The width and height of the button_canvas must be used as the reference for width and height for 'button_frame', not the width & height of the main window 'app_win'. Der Grund hierfür ist weil das 'button_frame' befindet sich auf der Fläche des 'button_canvas'. The reason for this is because the 'button_frame' is located within the 'button_canvas'. That means the 'buttonframe' is not directly on the 'button_canvas' but in a canvas object 'window'.
Following modifications are necessary:
1)
Here is the modified script with sizing of 'button_frame' (scrolling does not work!):
Here the script for placing widgets in 'canvas window objects':
wuf
Python programmers try to follow a certain styleguide by writing a script. If you have time, I would take a look at it. Contact the following link:
PEP 8 -- Style Guide for Python Code
https://www.python.org/dev/peps/pep-0008/
So my style differs from yours
weatherman wuf
--------------------------------------------
self._customGUI self.app_win
self._buttonFrame self.button_frame
self._buttonCanvas self.button_canvas
--------------------------------------------
The following script changes the size of the 'button_frame' depending on the change of the main window 'app_win'. The width and height of the button_canvas must be used as the reference for width and height for 'button_frame', not the width & height of the main window 'app_win'. Der Grund hierfür ist weil das 'button_frame' befindet sich auf der Fläche des 'button_canvas'. The reason for this is because the 'button_frame' is located within the 'button_canvas'. That means the 'buttonframe' is not directly on the 'button_canvas' but in a canvas object 'window'.
Following modifications are necessary:
1)
self.button_frame = tk.Frame(self.button_canvas, bg='yellow') #self.button_canvas['bg']) self.button_frame.pack() self.button_frame.propagate(False) self.button_canvas.create_window((0,0), window=self.button_frame, anchor="nw")2)
def update(self, event): if self.button_canvas.bbox('all') != None: region = self.button_canvas.bbox('all') self.button_canvas.config(scrollregion=region) self.button_frame.config(width=self.button_canvas.winfo_width(), height=self.button_canvas.winfo_height())To highlight the 'button_frame' I changed its background to 'bg = yellow'.
Here is the modified script with sizing of 'button_frame' (scrolling does not work!):
#!/usr/bin/env python # -*- coding: utf-8 -*- from functools import partial try: # Tkinter for Python 2.xx import Tkinter as tk except ImportError: # Tkinter for Python 3.xx import tkinter as tk APP_TITLE = "Srollable Canvas" APP_XPOS = 100 APP_YPOS = 100 APP_WIDTH = 325 APP_HEIGHT = 425 NUM_OF_BUTTONS = 20 BUTTONS = ['Button-{0:02d}'.format(nr) for nr in range(1, NUM_OF_BUTTONS+1)] class Application(tk.Frame): def __init__(self, app_win, **options): self.app_win = app_win self.app_win.protocol("WM_DELETE_WINDOW", self.close) tk.Frame.__init__(self, app_win, **options) self.grid_rowconfigure(0, weight=1) self.grid_columnconfigure(0, weight=1) self.button_canvas = tk.Canvas(self, bg='steelblue', highlightthickness=0) self.button_canvas.grid(row=0, column=0, sticky='wesn') self.yscrollbar = tk.Scrollbar(self, orient="vertical", width=14, command=self.button_canvas.yview) self.yscrollbar.grid(row=0, column=1, sticky='ns') self.xscrollbar = tk.Scrollbar(self, orient="horizontal", width=14, command=self.button_canvas.xview) self.xscrollbar.grid(row=1, column=0, sticky='we') self.button_canvas.configure( xscrollcommand=self.xscrollbar.set, yscrollcommand=self.yscrollbar.set) self.button_frame = tk.Frame(self.button_canvas, bg='yellow') #self.button_canvas['bg']) self.button_frame.pack() self.button_frame.propagate(False) self.button_canvas.create_window((0,0), window=self.button_frame, anchor="nw") for button in BUTTONS: button = tk.Button(self.button_frame, text=button, highlightthickness=0, command=partial(self.button_callback, button)) button.pack(padx=4, pady=2) self.bind_mouse_scroll(button, self.yscroll) self.button_canvas.bind('<Configure>', self.update) self.bind_mouse_scroll(self.button_canvas, self.yscroll) self.bind_mouse_scroll(self.xscrollbar, self.xscroll) self.bind_mouse_scroll(self.yscrollbar, self.yscroll) self.bind_mouse_scroll(self.button_frame, self.yscroll) self.button_canvas.focus_set() def bind_mouse_scroll(self, parent, mode): #~~ Windows only parent.bind("<MouseWheel>", mode) #~~ Unix only parent.bind("<Button-4>", mode) parent.bind("<Button-5>", mode) def yscroll(self, event): if event.num == 5 or event.delta < 0: self.button_canvas.yview_scroll(1, "unit") elif event.num == 4 or event.delta > 0: self.button_canvas.yview_scroll(-1, "unit") def xscroll(self, event): if event.num == 5 or event.delta < 0: self.button_canvas.xview_scroll(1, "unit") elif event.num == 4 or event.delta > 0: self.button_canvas.xview_scroll(-1, "unit") def update(self, event): if self.button_canvas.bbox('all') != None: region = self.button_canvas.bbox('all') self.button_canvas.config(scrollregion=region) self.button_frame.config(width=self.button_canvas.winfo_width(), height=self.button_canvas.winfo_height()) def button_callback(self, button): print(button) def close(self): print("Application-Shutdown") self.app_win.destroy() def main(): app_win = tk.Tk() app_win.title(APP_TITLE) app_win.geometry("+{}+{}".format(APP_XPOS, APP_YPOS)) app_win.geometry("{}x{}".format(APP_WIDTH, APP_HEIGHT)) app = Application(app_win) app.pack(fill='both', expand=True) app_win.mainloop() if __name__ == '__main__': main()If you now change the size of the main window 'app_win', the 'button_frame' always adapts the new size of the 'button_canvas'! Since the 'button_frame' is located in a canvas window object, its size automatically changes with the 'button_frame'. This means the largest object within the 'button_canvas' is the window object and not the arrangement of the buttons on the 'button_frame'! That's why the scrolling does not work anymore!. If you place each button in a separate 'canvas window object' and place it on the 'button_canvas' using the coordinates, the scrolling will work again! If you want to place additional widgets on the 'button_canvas', you have to put them in a 'canvas window object' and position them by means of coordinates.
Here the script for placing widgets in 'canvas window objects':
#!/usr/bin/env python # -*- coding: utf-8 -*- from functools import partial try: # Tkinter for Python 2.xx import Tkinter as tk except ImportError: # Tkinter for Python 3.xx import tkinter as tk APP_TITLE = "Srollable Canvas" APP_XPOS = 100 APP_YPOS = 100 APP_WIDTH = 325 APP_HEIGHT = 425 NUM_OF_BUTTONS = 20 BUTTONS = ['Button-{0:02d}'.format(nr) for nr in range(1, NUM_OF_BUTTONS+1)] class Application(tk.Frame): def __init__(self, app_win, **options): self.app_win = app_win self.app_win.protocol("WM_DELETE_WINDOW", self.close) tk.Frame.__init__(self, app_win, **options) self.grid_rowconfigure(0, weight=1) self.grid_columnconfigure(0, weight=1) self.button_canvas = tk.Canvas(self, bg='steelblue', highlightthickness=0) self.button_canvas.grid(row=0, column=0, sticky='wesn') self.yscrollbar = tk.Scrollbar(self, orient="vertical", width=14, command=self.button_canvas.yview) self.yscrollbar.grid(row=0, column=1, sticky='ns') self.xscrollbar = tk.Scrollbar(self, orient="horizontal", width=14, command=self.button_canvas.xview) self.xscrollbar.grid(row=1, column=0, sticky='we') self.button_canvas.configure( xscrollcommand=self.xscrollbar.set, yscrollcommand=self.yscrollbar.set) xpos = 0 ypos = 0 ygap = 30 for button in BUTTONS: button = tk.Button(self.button_canvas, text=button, highlightthickness=0, command=partial(self.button_callback, button)) button.pack(padx=4, pady=2) self.button_canvas.create_window((xpos, ypos), window=button, anchor="nw") ypos += ygap self.bind_mouse_scroll(button, self.yscroll) self.button_canvas.bind('<Configure>', self.update) self.bind_mouse_scroll(self.button_canvas, self.yscroll) self.bind_mouse_scroll(self.xscrollbar, self.xscroll) self.bind_mouse_scroll(self.yscrollbar, self.yscroll) self.button_canvas.focus_set() def bind_mouse_scroll(self, parent, mode): #~~ Windows only parent.bind("<MouseWheel>", mode) #~~ Unix only parent.bind("<Button-4>", mode) parent.bind("<Button-5>", mode) def yscroll(self, event): if event.num == 5 or event.delta < 0: self.button_canvas.yview_scroll(1, "unit") elif event.num == 4 or event.delta > 0: self.button_canvas.yview_scroll(-1, "unit") def xscroll(self, event): if event.num == 5 or event.delta < 0: self.button_canvas.xview_scroll(1, "unit") elif event.num == 4 or event.delta > 0: self.button_canvas.xview_scroll(-1, "unit") def update(self, event): if self.button_canvas.bbox('all') != None: region = self.button_canvas.bbox('all') self.button_canvas.config(scrollregion=region) def button_callback(self, button): print(button) def close(self): print("Application-Shutdown") self.app_win.destroy() def main(): app_win = tk.Tk() app_win.title(APP_TITLE) app_win.geometry("+{}+{}".format(APP_XPOS, APP_YPOS)) app_win.geometry("{}x{}".format(APP_WIDTH, APP_HEIGHT)) app = Application(app_win) app.pack(fill='both', expand=True) app_win.mainloop() if __name__ == '__main__': main()Have fun studying the whole.
wuf
