[英]Scrollbar in Canvas doesn't work - Tkinter Python
幾天來,我一直在努力為我的 canvas 小部件添加一個工作滾動條。 我正在開發一個小應用程序來顯示 excel 數據。 我已經嘗試了很多東西,但無法達到工作結果:/
我用“file_opener”function 填充 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()
由於使用grid()
或pack()
將小部件放入 canvas 不會更改滾動scrollregion
,因此不會激活鏈接到 canvas 的滾動條。
您需要創建一個框架並使用.create_window(...)
將其放入 canvas 中,然后將這些Text
和Checkbutton
小部件放入此框架中。 此外,您還需要在調整框架大小時更新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()
使用 tkinter 讓滾動條工作可能會很尷尬,尤其是在考慮網格重量等因素時( 我最近問了一個關於這個問題的問題)。
我在下面創建了您的代碼的最小版本,但為簡單起見,用框架替換了條目和按鈕 canvas 的布局,同時還最小化了文件打開器 function,現在只需要在下面的代碼中添加文件路徑跑步。
我在 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.