I am using Tkinter for a project, and I found in Stackoverflow a code to create a scrollbar, which I understood well. I wanted to scroll some buttons, which worked, but now when I try to scroll some grids (button and scales), it doesn’t work.
I have tried to manage my code with answers here and here, but I didn’t reach my goal!
#!/usr/bin/env python3 # -*- coding:utf-8 -*- # -------------------------------- Importation ------------------------------- # import tkinter as tk from tkinter import messagebox # ------------------------------ Initialisation ------------------------------ # root = tk.Tk() width_screen, height_screen = root.winfo_screenwidth(), root.winfo_screenheight() root.geometry("%dx%d+0+0" % (width_screen, height_screen)) # ----------------------- Creation of a list of sounds ----------------------- # wav_files = ["a.wav","b.wav","c.wav","d.wav","e.wav","f.wav","g.wav","h.wav","i.wav","j.wav","k.wav","l.wav","m.wav","n.wav","o.wav","p.wav","q.wav","r.wav","s.wav","t.wav","u.wav","v.wav","w.wav","x.wav","y.wav","z.wav","aa.wav","bb.wav","cc.wav","dd.wav","ee.wav","ff.wav"] # -------------------------- Vertical scrolled frame ------------------------- # class VerticalScrolledFrame(tk.Frame): def __init__(self, parent, *args, **kw): tk.Frame.__init__(self, parent, *args, **kw) # create a canvas object and a vertical scrollbar for scrolling it vscrollbar = tk.Scrollbar(self, orient=tk.VERTICAL) vscrollbar.grid(row=0, column=1, sticky='ns') canvas = tk.Canvas(self, bd=0, highlightthickness=0, yscrollcommand=vscrollbar.set, width=root.winfo_screenwidth(), height=root.winfo_screenheight()) canvas.grid(row=0, column=0, sticky="news") vscrollbar.config(command=canvas.yview) # reset the view #canvas.xview_moveto(0) #canvas.yview_moveto(0) # create a frame inside the canvas which will be scrolled with it self.interior = interior = tk.Frame(canvas) interior_id = canvas.create_window(0, 0, window=interior, anchor=tk.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) def _configure_canvas(event): if interior.winfo_reqwidth() != canvas.winfo_width(): # update the inner frame's width to fill the canvas canvas.itemconfigure(interior_id, width=canvas.winfo_width()) canvas.bind('<Configure>', _configure_canvas) # ------------------------------- Sound buttons ------------------------------ # class Make_sound: def __init__(self, name, parent): self.varbutton = tk.StringVar() self.varbutton.set("OFF") self.name = name self.parent = parent self.soundbuttoncreator() def launchsound(self): if self.varbutton.get() == "OFF": self.varbutton.set("ON") else: self.varbutton.set("OFF") def soundbuttoncreator(self): self.volumescale = tk.Scale(self.parent, orient='vertical', from_=0, to=10, resolution=0.1, tickinterval=2, label='Volume (db)', ) self.volumescale.grid(row=0,column=1, rowspan=2, sticky="nsew") self.faderscale = tk.Scale(self.parent, orient='horizontal', from_=0, to=10, resolution=0.1, tickinterval=2, label='Volume (db)') self.faderscale.grid(row=1,column=0, sticky="nsew") self.button = tk.Checkbutton(self.parent,text=self.name, indicatoron=False, selectcolor="green", background="red", onvalue="ON", offvalue="OFF") self.button.grid(row=0, column=0, sticky="nsew") def sounds_buttons(parent): for i in range(len(wav_files)): new_name = wav_files[i][:-4] globals()["wav_files"][i] = Make_sound(new_name,parent) # ---------------------------------------------------------------------------- # # Creation # # ---------------------------------------------------------------------------- # # ----------------------------- Buttons of sound ----------------------------- # scframe = VerticalScrolledFrame(root) scframe.pack(side=tk.LEFT) sounds_buttons(scframe.interior) root.mainloop()
EDIT 1: It seems that the output is just made of the last grid, because the text in the only button shown is ff, which corresponds to the last sound in the list. I didn’t have this problem with just buttons (and not grids): I could see every sounds and I had the scrolling bar active…
EDIT 2: The problem is solved, but now we have a new problem : putting a command to the checkbutton isn’t possible like that. You can see by yourself that the self.varbutton.set(“OFF) isn’t respected, the button is always on “ON”… Here is the code with the problem of command :
#!/usr/bin/env python3 # -*- coding:utf-8 -*- # -------------------------------- Importation ------------------------------- # import tkinter as tk from tkinter import messagebox # ------------------------------ Initialisation ------------------------------ # root = tk.Tk() width_screen, height_screen = root.winfo_screenwidth(), root.winfo_screenheight() root.geometry("%dx%d+0+0" % (width_screen, height_screen)) # ----------------------- Creation of a list of sounds ----------------------- # wav_files = ["a.wav","b.wav","c.wav","d.wav","e.wav","f.wav","g.wav","h.wav","i.wav","j.wav","k.wav","l.wav","m.wav","n.wav","o.wav","p.wav","q.wav","r.wav","s.wav","t.wav","u.wav","v.wav","w.wav","x.wav","y.wav","z.wav","aa.wav","bb.wav","cc.wav","dd.wav","ee.wav","ff.wav"] # -------------------------- Vertical scrolled frame ------------------------- # class VerticalScrolledFrame(tk.Frame): def __init__(self, parent, *args, **kw): tk.Frame.__init__(self, parent, *args, **kw) # create a canvas object and a vertical scrollbar for scrolling it vscrollbar = tk.Scrollbar(self, orient=tk.VERTICAL) vscrollbar.grid(row=0, column=1, sticky='ns') canvas = tk.Canvas(self, bd=0, highlightthickness=0, yscrollcommand=vscrollbar.set, width=root.winfo_screenwidth(), height=root.winfo_screenheight()) canvas.grid(row=0, column=0, sticky="news") vscrollbar.config(command=canvas.yview) # reset the view #canvas.xview_moveto(0) #canvas.yview_moveto(0) # create a frame inside the canvas which will be scrolled with it self.interior = interior = tk.Frame(canvas) interior_id = canvas.create_window(0, 0, window=interior, anchor=tk.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) def _configure_canvas(event): if interior.winfo_reqwidth() != canvas.winfo_width(): # update the inner frame's width to fill the canvas canvas.itemconfigure(interior_id, width=canvas.winfo_width()) canvas.bind('<Configure>', _configure_canvas) # ------------------------------- Sound buttons ------------------------------ # class Make_sound: def __init__(self, name, parent): self.varbutton = tk.StringVar() self.name = name self.parent = parent self.soundbuttoncreator() def launchsound(self): print(self.varbutton.get()) if self.varbutton.get() == 1: self.list=[] else: self.list.append("A") def soundbuttoncreator(self): self.frame = tk.Frame(self.parent) # create a frame to hold the widgets # use self.frame as parent instead of self.parent self.volumescale = tk.Scale(self.frame, orient='vertical', from_=0, to=10, resolution=0.1, tickinterval=2, label='Volume (db)', ) self.volumescale.grid(row=0,column=1, rowspan=2, sticky="nsew") self.faderscale = tk.Scale(self.frame, orient='horizontal', from_=0, to=10, resolution=0.1, tickinterval=2, label='Volume (db)') self.faderscale.grid(row=1,column=0, sticky="nsew") self.button = tk.Checkbutton(self.frame, text=self.name, indicatoron=False, selectcolor="green", background="red", variable=self.varbutton, command=self.launchsound) self.button.grid(row=0, column=0, sticky="nsew") self.frame.pack() # use pack() on the frame so new instance of `Make_sound` will not overlap the old instances def sounds_buttons(parent): for i in range(len(wav_files)): new_name = wav_files[i][:-4] globals()["wav_files"][i] = Make_sound(new_name,parent) # ---------------------------------------------------------------------------- # # Creation # # ---------------------------------------------------------------------------- # # ----------------------------- Buttons of sound ----------------------------- # scframe = VerticalScrolledFrame(root) scframe.pack(side=tk.LEFT) sounds_buttons(scframe.interior) root.mainloop()
EDIT 3: I edited my second code (see EDIT 2).
Advertisement
Answer
It is because you put all the set of Scale
and Checkbutton
into same location, so the last set will overlap the previous ones:
def soundbuttoncreator(self): self.volumescale = tk.Scale(self.parent, orient='vertical', from_=0, to=10, resolution=0.1, tickinterval=2, label='Volume (db)', ) self.volumescale.grid(row=0,column=1, rowspan=2, sticky="nsew") # same for all instances of Make_sound self.faderscale = tk.Scale(self.parent, orient='horizontal', from_=0, to=10, resolution=0.1, tickinterval=2, label='Volume (db)') self.faderscale.grid(row=1,column=0, sticky="nsew") # same for all instances of Make_sound self.button = tk.Checkbutton(self.parent,text=self.name, indicatoron=False, selectcolor="green", background="red", onvalue="ON", offvalue="OFF") self.button.grid(row=0, column=0, sticky="nsew") # same for all instances of Make_sound
You should put the set of widgets in a frame and use pack()
on the frame:
def soundbuttoncreator(self): self.frame = tk.Frame(self.parent) # create a frame to hold the widgets # use self.frame as parent instead of self.parent self.volumescale = tk.Scale(self.frame, orient='vertical', from_=0, to=10, resolution=0.1, tickinterval=2, label='Volume (db)', ) self.volumescale.grid(row=0,column=1, rowspan=2, sticky="nsew") self.faderscale = tk.Scale(self.frame, orient='horizontal', from_=0, to=10, resolution=0.1, tickinterval=2, label='Volume (db)') self.faderscale.grid(row=1,column=0, sticky="nsew") self.button = tk.Checkbutton(self.frame, text=self.name, indicatoron=False, selectcolor="green", background="red", onvalue="ON", offvalue="OFF", variable=self.varbutton) self.button.grid(row=0, column=0, sticky="nsew") self.frame.pack() # use pack() on the frame so new instance of `Make_sound` will not overlap the old instances