Canvas 中的滚动条不起作用 - Tkinter Python
Scrollbar in Canvas doesn't work - Tkinter Python
几天来,我一直在努力为我的 canvas 小部件添加一个工作滚动条。
我正在开发一个小应用程序来显示 excel 数据。我已经尝试了很多东西,但无法取得工作结果:/
我用“file_opener”函数填充 canvas2,我想将滚动条添加到 canvas2 的第 7 列。但是,在我之前的尝试中,滚动条只出现在第 0 行并且没有该功能。
我是一名自学初学者,非常感谢您的帮助。
这是它的样子:“https://ibb.co/W2d674g”
这是我的代码:
import tkinter
from tkinter import *
import pandas as pd
class App:
def __init__(self, window):
self.window = window
window.title("Excel Magician")
window.geometry("800x800")
self.canvas1 = tkinter.Canvas(window, width = 720, height = 200)
self.canvas1.grid(row=0, column=0)
self.frame1 = tkinter.Frame(window, width = 720,height = 20, bg = '#0ca274')
self.frame1.grid(row=1, column=0, pady=4)
self.canvas2 = tkinter.Canvas(window, width = 720,height = 300, bg = '#0ca274')
self.canvas2.grid(row=2, column=0, pady=1)
self.column_list = ['CLIENT','Column2','Column3','Column4','Column5']
for i in range(len(self.column_list)):
tkinter.Label(self.frame1, text= self.column_list[i], font=('Bahnschrift',10)).grid(row= 0, column= i, sticky='e', ipadx=50)
self.user_label = tkinter.Label(self.canvas1, text='USERNAME', font=('Bahnschrift',10))
self.canvas1.create_window(600, 60, window=self.user_label)
self.user_name = tkinter.Entry (self.canvas1)
self.canvas1.create_window(600, 80, window=self.user_name)
self.client_label = tkinter.Label(self.canvas1, text='CLIENT NAME', font=('Bahnschrift',10))
self.canvas1.create_window(600, 100, window=self.client_label)
self.client_name = tkinter.Entry (self.canvas1)
self.canvas1.create_window(600, 120, window=self.client_name)
self.button1 = tkinter.Button(text='Find Client',font=('Bahnschrift',10), command=self.file_opener)
self.canvas1.create_window(600, 150, window=self.button1)
def file_opener(self):
self.name = self.user_name.get()
self.xl= pd.read_excel(f"C:/Users/leven\Desktop/{self.name}'s Portfolio.xlsm", sheet_name='CM DATA')
self.client = self.client_name.get()
self.result = self.xl[self.xl.Client.str.contains(self.client, regex=False, case=False)][['Client','Column2','Column3','Column4','Column5']]
self.client_name.delete(0, 'end')
self.active_state=[]
for widget in self.canvas2.winfo_children():
widget.destroy()
for x in range(len(self.result)):
for y in range(len(self.result.columns)):
textbox = Text(self.canvas2, width=20, height=2,font=('Bahnschrift',10))
textbox.grid(row=x,column=y, padx=2, pady=2)
textbox.insert(END, self.result.iloc[x,y])
var = tkinter.IntVar()
self.checkbox = Checkbutton(self.canvas2,variable=var, onvalue=1, offvalue=0, relief=SUNKEN)
self.checkbox.grid(row=x, column=6, padx=2, pady=2, ipadx=2, ipady=2)
self.active_state.append(var)
if __name__ == "__main__":
root = Tk()
my_gui = App(root)
root.mainloop()
使用 tkinter 使滚动条工作可能很尴尬,尤其是在考虑网格权重 () 等问题时。
我在下面创建了您的代码的最小版本,但为简单起见,将条目和按钮 canvas 的布局替换为框架,同时也最小化了文件打开器功能,现在只需要要在下面的代码中添加到 运行.
的文件路径
我在 canvas/scrollbar gui 部分添加了一些评论,以便更容易直观地显示元素的位置以及它们之间的关系。
import tkinter
from tkinter import *
import pandas as pd
class App:
def __init__(self, window):
self.window = window
window.columnconfigure(0, weight=1)
window.rowconfigure(1, weight=1)
window.title("Excel Magician")
window.geometry("800x800")
# === GUI for entries & button ===
# Main frame
self.frame = tkinter.Frame(window)
self.frame.grid(row=0, column=0, columnspan=2, sticky='w')
# label User
self.user_label = tkinter.Label(self.frame, text='USERNAME')
self.user_label.grid(row=0, column=0)
# entry User
self.user_name = tkinter.Entry(self.frame)
self.user_name.grid(row=0, column=1)
# label Client
self.client_label = tkinter.Label(self.frame, text='CLIENT NAME')
self.client_label.grid(row=1, column=0)
# Entry Client
self.client_name = tkinter.Entry(self.frame)
self.client_name.grid(row=1, column=1)
# Button
self.button1 = tkinter.Button(self.frame, text='Find Client', command=self.file_opener)
self.button1.grid(row=2, column=1)
# === GUI for canvas and scrollbar ===
# 1) Create a frame (may not be necessary depending on grid method used)
self.frame1 = tkinter.Frame(window)
self.frame1.grid(row=1, column=0, sticky='nsew')
self.frame1.columnconfigure(0, weight=1)
self.frame1.rowconfigure(1, weight=1)
# 2) Canvas goes inside frame
self.canvas = tkinter.Canvas(self.frame1)
self.canvas.grid(row=1, column=0, sticky='nsew')
# 3) Scroll Sidebar also goes inside this frame in next column
self.scroll_y = tkinter.Scrollbar(self.frame1, orient='vertical', command=self.canvas.yview)
self.scroll_y.grid(row=1, column=1, sticky='ns')
# 4) Sub-frame goes inside of the canvas
self.canvas_sub_frame = tkinter.Frame(self.canvas)
# Column Header population
self.column_list = ['CLIENT', 'Column2', 'Column3', 'Column4', 'Column5']
for i in range(len(self.column_list)):
tkinter.Label(self.canvas_sub_frame, text=self.column_list[i]).grid(row=0, column=i, sticky='ew')
self.canvas_sub_frame.columnconfigure(i, weight=1)
# 5) Create Scroll Y & table expansion events
self.canvas.create_window(0, 0, anchor='nw', window=self.canvas_sub_frame, tag='window')
self.canvas_sub_frame.bind('<Configure>', self.config_frame) # configure to allow scrolling
self.canvas.bind('<Configure>', self.canvas_config) # configures to allow expansion of window
# Scroll bar function
def config_frame(self, event):
self.canvas.configure(scrollregion=self.canvas.bbox('all'), yscrollcommand=self.scroll_y.set)
# Resizing function
def canvas_config(self, event):
canvas_width = event.width
event.widget.itemconfig('window', width=canvas_width)
def file_opener(self):
xl = pd.read_excel(r'Filepath\Test_File.xlsx', sheet_name='Sheet1')
for x in range(len(xl)):
for y in range(len(xl.columns)):
textbox = Text(self.canvas_sub_frame, width=15, height=2)
textbox.grid(row=x+1, column=y, sticky='ew')
textbox.insert(END, xl.iloc[x, y])
checkbox = Checkbutton(self.canvas_sub_frame)
checkbox.grid(row=x+1, column=6)
if __name__ == "__main__":
root = Tk()
my_gui = App(root)
root.mainloop()
由于使用 grid()
或 pack()
将小部件放入 canvas 不会更改 scrollregion
,因此链接到 canvas 的滚动条不会被激活。
您需要创建一个框架并使用 .create_window(...)
将其放入 canvas,然后将那些 Text
和 Checkbutton
小部件放入该框架。此外,您还需要在调整框架大小时更新 canvas 的 scrollregion
,以便可以激活附加的滚动条。
以下是根据您的修改后的代码:
import tkinter
import pandas as pd
class App:
def __init__(self, window):
self.window = window
window.title("Excel Magician")
window.geometry("800x800")
self.canvas1 = tkinter.Canvas(window, width = 720, height = 200)
self.canvas1.grid(row=0, column=0)
self.frame1 = tkinter.Frame(window, width = 720,height = 20, bg = '#0ca274')
self.frame1.grid(row=1, column=0, pady=4)
self.canvas2 = tkinter.Canvas(window, width = 720,height = 300, bg = '#0ca274')
self.canvas2.grid(row=2, column=0, pady=1, sticky='ew') # added sticky='ew'
self.column_list = ['CLIENT','Column2','Column3','Column4','Column5']
for i in range(len(self.column_list)):
tkinter.Label(self.frame1, text= self.column_list[i], font=('Bahnschrift',10)).grid(row= 0, column= i, sticky='e', ipadx=50)
self.user_label = tkinter.Label(self.canvas1, text='USERNAME', font=('Bahnschrift',10))
self.canvas1.create_window(600, 60, window=self.user_label)
self.user_name = tkinter.Entry (self.canvas1)
self.canvas1.create_window(600, 80, window=self.user_name)
self.client_label = tkinter.Label(self.canvas1, text='CLIENT NAME', font=('Bahnschrift',10))
self.canvas1.create_window(600, 100, window=self.client_label)
self.client_name = tkinter.Entry (self.canvas1)
self.canvas1.create_window(600, 120, window=self.client_name)
self.button1 = tkinter.Button(text='Find Client',font=('Bahnschrift',10), command=self.file_opener)
self.canvas1.create_window(600, 150, window=self.button1)
# create the scrollable frame and the scrollbar
self.internal = tkinter.Frame(self.canvas2)
self.internal.bind('<Configure>', lambda e: self.canvas2.config(scrollregion=self.canvas2.bbox('all')))
self.canvas2.create_window(0, 0, window=self.internal, anchor='nw')
self.scrollbar = tkinter.Scrollbar(window, command=self.canvas2.yview)
self.scrollbar.grid(row=2, column=1, sticky='ns')
self.canvas2.config(yscrollcommand=self.scrollbar.set)
def file_opener(self):
self.name = self.user_name.get()
self.xl= pd.read_excel(f"C:/Users/leven/Desktop/{self.name}'s Portfolio.xlsm", sheet_name='CM DATA')
self.client = self.client_name.get()
self.result = self.xl[self.xl.Client.str.contains(self.client, regex=False, case=False)][['Client','Column2','Column3','Column4','Column5']]
self.client_name.delete(0, 'end')
self.active_state=[]
# clear existing widgets in self.internal
for widget in self.internal.winfo_children():
widget.destroy()
for x in range(len(self.result)):
for y in range(len(self.result.columns)):
# created inside self.internal
textbox = tkinter.Text(self.internal, width=20, height=2,font=('Bahnschrift',10))
textbox.grid(row=x,column=y, padx=2, pady=2)
textbox.insert(tkinter.END, self.result.iloc[x,y])
var = tkinter.IntVar()
# created inside self.internal
self.checkbox = tkinter.Checkbutton(self.internal,variable=var, onvalue=1, offvalue=0, relief=tkinter.SUNKEN)
self.checkbox.grid(row=x, column=6, padx=2, pady=2, ipadx=2, ipady=2)
self.active_state.append(var)
if __name__ == "__main__":
root = tkinter.Tk()
my_gui = App(root)
root.mainloop()
几天来,我一直在努力为我的 canvas 小部件添加一个工作滚动条。 我正在开发一个小应用程序来显示 excel 数据。我已经尝试了很多东西,但无法取得工作结果:/
我用“file_opener”函数填充 canvas2,我想将滚动条添加到 canvas2 的第 7 列。但是,在我之前的尝试中,滚动条只出现在第 0 行并且没有该功能。
我是一名自学初学者,非常感谢您的帮助。
这是它的样子:“https://ibb.co/W2d674g”
这是我的代码:
import tkinter
from tkinter import *
import pandas as pd
class App:
def __init__(self, window):
self.window = window
window.title("Excel Magician")
window.geometry("800x800")
self.canvas1 = tkinter.Canvas(window, width = 720, height = 200)
self.canvas1.grid(row=0, column=0)
self.frame1 = tkinter.Frame(window, width = 720,height = 20, bg = '#0ca274')
self.frame1.grid(row=1, column=0, pady=4)
self.canvas2 = tkinter.Canvas(window, width = 720,height = 300, bg = '#0ca274')
self.canvas2.grid(row=2, column=0, pady=1)
self.column_list = ['CLIENT','Column2','Column3','Column4','Column5']
for i in range(len(self.column_list)):
tkinter.Label(self.frame1, text= self.column_list[i], font=('Bahnschrift',10)).grid(row= 0, column= i, sticky='e', ipadx=50)
self.user_label = tkinter.Label(self.canvas1, text='USERNAME', font=('Bahnschrift',10))
self.canvas1.create_window(600, 60, window=self.user_label)
self.user_name = tkinter.Entry (self.canvas1)
self.canvas1.create_window(600, 80, window=self.user_name)
self.client_label = tkinter.Label(self.canvas1, text='CLIENT NAME', font=('Bahnschrift',10))
self.canvas1.create_window(600, 100, window=self.client_label)
self.client_name = tkinter.Entry (self.canvas1)
self.canvas1.create_window(600, 120, window=self.client_name)
self.button1 = tkinter.Button(text='Find Client',font=('Bahnschrift',10), command=self.file_opener)
self.canvas1.create_window(600, 150, window=self.button1)
def file_opener(self):
self.name = self.user_name.get()
self.xl= pd.read_excel(f"C:/Users/leven\Desktop/{self.name}'s Portfolio.xlsm", sheet_name='CM DATA')
self.client = self.client_name.get()
self.result = self.xl[self.xl.Client.str.contains(self.client, regex=False, case=False)][['Client','Column2','Column3','Column4','Column5']]
self.client_name.delete(0, 'end')
self.active_state=[]
for widget in self.canvas2.winfo_children():
widget.destroy()
for x in range(len(self.result)):
for y in range(len(self.result.columns)):
textbox = Text(self.canvas2, width=20, height=2,font=('Bahnschrift',10))
textbox.grid(row=x,column=y, padx=2, pady=2)
textbox.insert(END, self.result.iloc[x,y])
var = tkinter.IntVar()
self.checkbox = Checkbutton(self.canvas2,variable=var, onvalue=1, offvalue=0, relief=SUNKEN)
self.checkbox.grid(row=x, column=6, padx=2, pady=2, ipadx=2, ipady=2)
self.active_state.append(var)
if __name__ == "__main__":
root = Tk()
my_gui = App(root)
root.mainloop()
使用 tkinter 使滚动条工作可能很尴尬,尤其是在考虑网格权重 (
我在下面创建了您的代码的最小版本,但为简单起见,将条目和按钮 canvas 的布局替换为框架,同时也最小化了文件打开器功能,现在只需要要在下面的代码中添加到 运行.
的文件路径我在 canvas/scrollbar gui 部分添加了一些评论,以便更容易直观地显示元素的位置以及它们之间的关系。
import tkinter
from tkinter import *
import pandas as pd
class App:
def __init__(self, window):
self.window = window
window.columnconfigure(0, weight=1)
window.rowconfigure(1, weight=1)
window.title("Excel Magician")
window.geometry("800x800")
# === GUI for entries & button ===
# Main frame
self.frame = tkinter.Frame(window)
self.frame.grid(row=0, column=0, columnspan=2, sticky='w')
# label User
self.user_label = tkinter.Label(self.frame, text='USERNAME')
self.user_label.grid(row=0, column=0)
# entry User
self.user_name = tkinter.Entry(self.frame)
self.user_name.grid(row=0, column=1)
# label Client
self.client_label = tkinter.Label(self.frame, text='CLIENT NAME')
self.client_label.grid(row=1, column=0)
# Entry Client
self.client_name = tkinter.Entry(self.frame)
self.client_name.grid(row=1, column=1)
# Button
self.button1 = tkinter.Button(self.frame, text='Find Client', command=self.file_opener)
self.button1.grid(row=2, column=1)
# === GUI for canvas and scrollbar ===
# 1) Create a frame (may not be necessary depending on grid method used)
self.frame1 = tkinter.Frame(window)
self.frame1.grid(row=1, column=0, sticky='nsew')
self.frame1.columnconfigure(0, weight=1)
self.frame1.rowconfigure(1, weight=1)
# 2) Canvas goes inside frame
self.canvas = tkinter.Canvas(self.frame1)
self.canvas.grid(row=1, column=0, sticky='nsew')
# 3) Scroll Sidebar also goes inside this frame in next column
self.scroll_y = tkinter.Scrollbar(self.frame1, orient='vertical', command=self.canvas.yview)
self.scroll_y.grid(row=1, column=1, sticky='ns')
# 4) Sub-frame goes inside of the canvas
self.canvas_sub_frame = tkinter.Frame(self.canvas)
# Column Header population
self.column_list = ['CLIENT', 'Column2', 'Column3', 'Column4', 'Column5']
for i in range(len(self.column_list)):
tkinter.Label(self.canvas_sub_frame, text=self.column_list[i]).grid(row=0, column=i, sticky='ew')
self.canvas_sub_frame.columnconfigure(i, weight=1)
# 5) Create Scroll Y & table expansion events
self.canvas.create_window(0, 0, anchor='nw', window=self.canvas_sub_frame, tag='window')
self.canvas_sub_frame.bind('<Configure>', self.config_frame) # configure to allow scrolling
self.canvas.bind('<Configure>', self.canvas_config) # configures to allow expansion of window
# Scroll bar function
def config_frame(self, event):
self.canvas.configure(scrollregion=self.canvas.bbox('all'), yscrollcommand=self.scroll_y.set)
# Resizing function
def canvas_config(self, event):
canvas_width = event.width
event.widget.itemconfig('window', width=canvas_width)
def file_opener(self):
xl = pd.read_excel(r'Filepath\Test_File.xlsx', sheet_name='Sheet1')
for x in range(len(xl)):
for y in range(len(xl.columns)):
textbox = Text(self.canvas_sub_frame, width=15, height=2)
textbox.grid(row=x+1, column=y, sticky='ew')
textbox.insert(END, xl.iloc[x, y])
checkbox = Checkbutton(self.canvas_sub_frame)
checkbox.grid(row=x+1, column=6)
if __name__ == "__main__":
root = Tk()
my_gui = App(root)
root.mainloop()
由于使用 grid()
或 pack()
将小部件放入 canvas 不会更改 scrollregion
,因此链接到 canvas 的滚动条不会被激活。
您需要创建一个框架并使用 .create_window(...)
将其放入 canvas,然后将那些 Text
和 Checkbutton
小部件放入该框架。此外,您还需要在调整框架大小时更新 canvas 的 scrollregion
,以便可以激活附加的滚动条。
以下是根据您的修改后的代码:
import tkinter
import pandas as pd
class App:
def __init__(self, window):
self.window = window
window.title("Excel Magician")
window.geometry("800x800")
self.canvas1 = tkinter.Canvas(window, width = 720, height = 200)
self.canvas1.grid(row=0, column=0)
self.frame1 = tkinter.Frame(window, width = 720,height = 20, bg = '#0ca274')
self.frame1.grid(row=1, column=0, pady=4)
self.canvas2 = tkinter.Canvas(window, width = 720,height = 300, bg = '#0ca274')
self.canvas2.grid(row=2, column=0, pady=1, sticky='ew') # added sticky='ew'
self.column_list = ['CLIENT','Column2','Column3','Column4','Column5']
for i in range(len(self.column_list)):
tkinter.Label(self.frame1, text= self.column_list[i], font=('Bahnschrift',10)).grid(row= 0, column= i, sticky='e', ipadx=50)
self.user_label = tkinter.Label(self.canvas1, text='USERNAME', font=('Bahnschrift',10))
self.canvas1.create_window(600, 60, window=self.user_label)
self.user_name = tkinter.Entry (self.canvas1)
self.canvas1.create_window(600, 80, window=self.user_name)
self.client_label = tkinter.Label(self.canvas1, text='CLIENT NAME', font=('Bahnschrift',10))
self.canvas1.create_window(600, 100, window=self.client_label)
self.client_name = tkinter.Entry (self.canvas1)
self.canvas1.create_window(600, 120, window=self.client_name)
self.button1 = tkinter.Button(text='Find Client',font=('Bahnschrift',10), command=self.file_opener)
self.canvas1.create_window(600, 150, window=self.button1)
# create the scrollable frame and the scrollbar
self.internal = tkinter.Frame(self.canvas2)
self.internal.bind('<Configure>', lambda e: self.canvas2.config(scrollregion=self.canvas2.bbox('all')))
self.canvas2.create_window(0, 0, window=self.internal, anchor='nw')
self.scrollbar = tkinter.Scrollbar(window, command=self.canvas2.yview)
self.scrollbar.grid(row=2, column=1, sticky='ns')
self.canvas2.config(yscrollcommand=self.scrollbar.set)
def file_opener(self):
self.name = self.user_name.get()
self.xl= pd.read_excel(f"C:/Users/leven/Desktop/{self.name}'s Portfolio.xlsm", sheet_name='CM DATA')
self.client = self.client_name.get()
self.result = self.xl[self.xl.Client.str.contains(self.client, regex=False, case=False)][['Client','Column2','Column3','Column4','Column5']]
self.client_name.delete(0, 'end')
self.active_state=[]
# clear existing widgets in self.internal
for widget in self.internal.winfo_children():
widget.destroy()
for x in range(len(self.result)):
for y in range(len(self.result.columns)):
# created inside self.internal
textbox = tkinter.Text(self.internal, width=20, height=2,font=('Bahnschrift',10))
textbox.grid(row=x,column=y, padx=2, pady=2)
textbox.insert(tkinter.END, self.result.iloc[x,y])
var = tkinter.IntVar()
# created inside self.internal
self.checkbox = tkinter.Checkbutton(self.internal,variable=var, onvalue=1, offvalue=0, relief=tkinter.SUNKEN)
self.checkbox.grid(row=x, column=6, padx=2, pady=2, ipadx=2, ipady=2)
self.active_state.append(var)
if __name__ == "__main__":
root = tkinter.Tk()
my_gui = App(root)
root.mainloop()