簡體   English   中英

Canvas 中的滾動條不起作用 - Tkinter Python

[英]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 中,然后將這些TextCheckbutton小部件放入此框架中。 此外,您還需要在調整框架大小時更新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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM