[英]Scrollbar in Canvas doesn't work - Tkinter Python
I have been struggling to add a working scrollbar to my canvas widget for days.几天来,我一直在努力为我的 canvas 小部件添加一个工作滚动条。 I'm working on a small app to show excel data.
我正在开发一个小应用程序来显示 excel 数据。 I have tried so many things but couldn't achieve a working result:/
我已经尝试了很多东西,但无法达到工作结果:/
I populate canvas2 with "file_opener" function, and I would like to add the scrollbar to the 7th column of canvas2.我用“file_opener”function 填充 canvas2,我想将滚动条添加到 canvas2 的第 7 列。 However, in my previous attempts the scrollbar was appearing only in row 0 and without the functionality.
但是,在我之前的尝试中,滚动条只出现在第 0 行,并且没有该功能。
I would greatly appreciate your help as I'm a self-learning beginner.我非常感谢您的帮助,因为我是一个自学初学者。
This is how it looks: "https://ibb.co/W2d674g"这就是它的外观:“https://ibb.co/W2d674g”
Here is my code:这是我的代码:
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()
As putting widgets into a canvas using grid()
or pack()
does not change the scrollregion
, so the scrollbar linked to the canvas will not be activated.由于使用
grid()
或pack()
将小部件放入 canvas 不会更改滚动scrollregion
,因此不会激活链接到 canvas 的滚动条。
You need to create a frame and put it into the canvas using .create_window(...)
and then put those Text
and Checkbutton
widgets into this frame.您需要创建一个框架并使用
.create_window(...)
将其放入 canvas 中,然后将这些Text
和Checkbutton
小部件放入此框架中。 Also you need to update the scrollregion
of the canvas when the frame is resized, so that the attached scrollbar can be activated.此外,您还需要在调整框架大小时更新
scrollregion
的滚动区域,以便激活附加的滚动条。
Below is a modified code based on yours:以下是根据您的修改后的代码:
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()
Getting scrollbars to work can be awkward with tkinter, especially when also accounting for things like grid weight ( I asked a question about that myself recently ).使用 tkinter 让滚动条工作可能会很尴尬,尤其是在考虑网格重量等因素时( 我最近问了一个关于这个问题的问题)。
I've created a minimal version of your code below but replaced the layout of the entries & button canvas with a frame for simplicity, as well as also minimizing the file opener function, which now just needs the filepath to be added in the code below to run.我在下面创建了您的代码的最小版本,但为简单起见,用框架替换了条目和按钮 canvas 的布局,同时还最小化了文件打开器 function,现在只需要在下面的代码中添加文件路径跑步。
I've added some comments to the canvas/scrollbar gui section just so its easier to visualise placement of the elements and how they relate to one another.我在 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')
self.canvas.columnconfigure(0, weight=1)
# 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')
self.scroll_y.columnconfigure(0, weight=1)
# 4) Sub-frame goes inside of the canvas
self.canvas_sub_frame = tkinter.Frame(self.canvas)
self.canvas_sub_frame.grid(row=1, column=0)
self.canvas_sub_frame.rowconfigure(0, weight=1)
# 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
# 5) Scroll bar function
def config_frame(self, event):
self.canvas.configure(scrollregion=self.canvas.bbox('all'), yscrollcommand=self.scroll_y.set)
# 5) 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\file.xlsx')
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()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.