我无法在 canvas (tkinter) 的框架中滚动网格
I can't scroll grids in frames in canvas (tkinter)
我在一个项目中使用Tkinter,我在Whosebug 中找到了一个创建滚动条的代码,我很理解。我想滚动一些按钮,这很有效,但现在当我尝试滚动一些网格(按钮和刻度)时,它不起作用。
我尝试用答案 and here 来管理我的代码,但我没有达到我的目标!
#!/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()
编辑 1:
似乎输出只是由最后一个网格组成,因为显示的唯一按钮中的文本是 ff,它对应于列表中的最后一个声音。
我只用按钮(而不是网格)没有这个问题:我可以看到每一个声音,我有滚动条活动...
编辑 2:
问题解决了,但现在我们遇到了一个新问题:不可能像那样向复选按钮发出命令。您可以自己看到 self.varbutton.set("OFF) 不受尊重,按钮始终处于"ON"状态...
这是有命令问题的代码:
#!/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()
编辑 3:
我编辑了我的第二个代码(见编辑 2)。
因为你把Scale
和Checkbutton
的所有set放在了同一个位置,所以最后一组会和前面的重叠:
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
您应该将小部件集放在框架中并在框架上使用 pack()
:
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
我在一个项目中使用Tkinter,我在Whosebug 中找到了一个创建滚动条的代码,我很理解。我想滚动一些按钮,这很有效,但现在当我尝试滚动一些网格(按钮和刻度)时,它不起作用。
我尝试用答案
#!/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()
编辑 1: 似乎输出只是由最后一个网格组成,因为显示的唯一按钮中的文本是 ff,它对应于列表中的最后一个声音。 我只用按钮(而不是网格)没有这个问题:我可以看到每一个声音,我有滚动条活动...
编辑 2: 问题解决了,但现在我们遇到了一个新问题:不可能像那样向复选按钮发出命令。您可以自己看到 self.varbutton.set("OFF) 不受尊重,按钮始终处于"ON"状态... 这是有命令问题的代码:
#!/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()
编辑 3: 我编辑了我的第二个代码(见编辑 2)。
因为你把Scale
和Checkbutton
的所有set放在了同一个位置,所以最后一组会和前面的重叠:
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
您应该将小部件集放在框架中并在框架上使用 pack()
:
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