【问题标题】:Tkinter Scrollbars with labels, canvas and frames带有标签、画布和框架的 Tkinter 滚动条
【发布时间】:2020-07-31 12:02:12
【问题描述】:

我想创建一个页面,其中右侧有一些标签,左侧有一些其他标签以及它们各自的滚动条。但我没能做到。

from tkinter import *

root = Tk()

root.columnconfigure(0, weight=1)
root.columnconfigure(2, weight=1)

canvasL = Canvas(root, bg='blue')
canvasL.grid(row=0, column=0, sticky="news")

canvasR = Canvas(root, bg='blue')
canvasR.grid(row=0, column=2, sticky="news")

frameL = Frame(canvasL, bg='red', width=1000)
frameL.grid(row=0, column=0, sticky="news")

frameR = Frame(canvasR, bg='red')
frameR.grid(row=0, column=0, sticky="news")

frameL.grid_propagate(False)
frameR.grid_propagate(False)

S1 = Scrollbar(frameL, orient="vertical", command=canvasL.yview)
S1.grid(row=0, column=1, sticky="news")

S2 = Scrollbar(frameR, orient="vertical", command=canvasR.yview)
S2.grid(row=0, column=3, sticky="news")

canvasL.configure(yscrollcommand=S1.set)
canvasL.configure(scrollregion=canvasL.bbox("all"))

canvasR.configure(yscrollcommand=S2.set)
canvasR.configure(scrollregion=canvasR.bbox("all"))

canvasL.create_window((0, 0), anchor='nw', window=frameL)
canvasR.create_window((0, 0), anchor='nw', window=frameR)

for i in range(0, 40):
    labelName = Label(frameL, text="Name : " + str(i), bg='#F5F5F5')
    labelName.grid(row=i, column=0)
    labelName = Label(frameR, text="Name : " + str(i), bg='#F5F5F5')
    labelName.grid(row=i, column=2)

root.mainloop()

如果您测试此代码,您会发现存在问题。你能帮我吗 ? 提前谢谢你。

【问题讨论】:

    标签: python tkinter tkinter-canvas


    【解决方案1】:

    首先你不应该执行以下两行:

    frameL.grid(row=0, column=0, sticky="news")
    frameR.grid(row=0, column=0, sticky="news")
    

    因为您不应该使用 grid()pack()place() 将小部件放入画布。并且您稍后使用create_window(...) 将它们放入画布中。

    两个滚动条的第二个父级应该是root

    S1 = Scrollbar(root, orient="vertical", command=canvasL.yview)
    S1.grid(row=0, column=1, sticky="ns")
    
    S2 = Scrollbar(root, orient="vertical", command=canvasR.yview)
    S2.grid(row=0, column=3, sticky="ns")
    

    另外你也不应该执行以下两行:

    frameL.grid_propagate(False)
    frameR.grid_propagate(False)
    

    因为他们可能使两个框架的高度为零。

    最后,在调用root.update()之后还要调用以下两行:

    root.update()
    canvasL.configure(scrollregion=canvasL.bbox("all"))
    canvasR.configure(scrollregion=canvasR.bbox("all"))
    

    但最好在调整框架大小时更新scrollregion

    frameL.bind('<Configure>', lambda e: canvasL.config(scrollregion=canvasL.bbox('all')))
    frameR.bind('<Configure>', lambda e: canvasR.config(scrollregion=canvasR.bbox('all')))
    

    以下是根据您的修改的示例:

    from tkinter import *
    
    root = Tk()
    
    root.columnconfigure(0, weight=1)
    root.columnconfigure(2, weight=1)
    
    canvasL = Canvas(root, bg='blue', highlightthickness=0)
    canvasL.grid(row=0, column=0, sticky="news")
    
    canvasR = Canvas(root, bg='blue', highlightthickness=0)
    canvasR.grid(row=0, column=2, sticky="news")
    
    frameL = Frame(canvasL, bg='red', width=1000)
    #frameL.grid(row=0, column=0, sticky="news")
    
    frameR = Frame(canvasR, bg='red')
    #frameR.grid(row=0, column=0, sticky="news")
    
    #frameL.grid_propagate(False)
    #frameR.grid_propagate(False)
    
    S1 = Scrollbar(root, orient="vertical", command=canvasL.yview)
    S1.grid(row=0, column=1, sticky="ns")
    
    S2 = Scrollbar(root, orient="vertical", command=canvasR.yview)
    S2.grid(row=0, column=3, sticky="ns")
    
    canvasL.configure(yscrollcommand=S1.set)
    canvasR.configure(yscrollcommand=S2.set)
    
    canvasL.create_window((0, 0), anchor='nw', window=frameL)
    canvasR.create_window((0, 0), anchor='nw', window=frameR)
    
    for i in range(0, 40):
        labelName = Label(frameL, text="Name : " + str(i), bg='#F5F5F5')
        labelName.grid(row=i, column=0)
        labelName = Label(frameR, text="Name : " + str(i), bg='#F5F5F5')
        labelName.grid(row=i, column=2)
    
    root.update()
    canvasL.configure(scrollregion=canvasL.bbox("all"))
    canvasR.configure(scrollregion=canvasR.bbox("all"))
    
    # better update scrollregion upon resize of frame
    #frameL.bind('<Configure>', lambda e: canvasL.config(scrollregion=canvasL.bbox('all')))
    #frameR.bind('<Configure>', lambda e: canvasR.config(scrollregion=canvasR.bbox('all')))
    
    root.mainloop()
    

    【讨论】:

    • 非常感谢您非常有趣的回答。但是您知道如何将框架置于其区域的中心吗?还有如何让鼠标滚轮上下移动的可能性?
    【解决方案2】:

    检查我的答案:

    对于canvas 上的scroll widget,请按照以下步骤操作:

    1. 创建第 1 帧,这将包含画布和滚动条
    2. 创建将在画布上滚动的第 2 帧,您可以在此帧上网格化任何小部件 但您需要使用canvas.create_window 创建窗口。

    您可以在评论中讨论额外的问题。

    import tkinter as tk
    from tkinter import ttk
    
    root = tk.Tk()
    root.geometry('800x400+0+0')
    root.columnconfigure(0, weight=1)
    root.columnconfigure(1, weight=1)
    root.rowconfigure(0, weight=1)
    
    ########################################################################
    ######## Left Side ####################################################
    left_container = tk.Frame(root, bg='green')
    left_container.grid(row=0, column=0, sticky='nsew', padx=(0, 2))
    left_container.columnconfigure(0, weight=1)
    left_container.rowconfigure(0, weight=1)
    
    left_canvas = tk.Canvas(left_container, bg='orange')
    left_canvas.grid(row=0, column=0, sticky='nsew')
    
    left_scrollbar = tk.Scrollbar(left_container, orient='vertical', command=left_canvas.yview)
    left_scrollbar.grid(row=0, column=1, sticky='nsew')
    left_canvas['yscrollcommand'] = left_scrollbar.set
    
    left_canvas.columnconfigure(0, weight=1)
    left_canvas.rowconfigure(0, weight=1)
    
    left_final_window = tk.Frame(left_canvas, bg='green')
    left_canvas.create_window((0, 0), window=left_final_window, anchor='nw', tags='expand1')
    left_final_window.columnconfigure(0, weight=1)
    
    for i in range(1, 51):
        label = tk.Label(left_final_window, text=f'Manish Pushpam ({i})')
        label.grid(row=i-1, column=0, sticky='nsew', pady=(0, 2))
    
    
    left_canvas.bind('<Configure>', lambda event: left_canvas.itemconfigure('expand1', width=event.width))
    left_final_window.update_idletasks()
    left_canvas.config(scrollregion=left_canvas.bbox('all'))
    ############### Scroll Using Mouse Wheel ###############
    def scroll(event, widget):
        widget.yview_scroll(int(-1 * (event.delta / 120)), "units")
    
    
    def final_scroll(event, widget, func):
        widget.bind_all("<MouseWheel>", func)
    
    
    def stop_scroll(event, widget):
        widget.unbind_all("<MouseWheel>")
    
    
    left_canvas.bind("<Enter>", lambda event: final_scroll(event, left_canvas, lambda event: scroll(event, left_canvas)))
    left_canvas.bind("<Leave>", lambda event: stop_scroll(event, left_canvas))
    ########################################################################
    ######## Right Side ####################################################
    right_container = tk.Frame(root, bg='orange')
    right_container.grid(row=0, column=1, sticky='nsew')
    right_container.columnconfigure(0, weight=1)
    right_container.rowconfigure(0, weight=1)
    
    right_canvas = tk.Canvas(right_container, bg='red')
    right_canvas.grid(row=0, column=0, sticky='nsew')
    
    right_scrollbar = tk.Scrollbar(right_container, orient='vertical', command=right_canvas.yview)
    right_scrollbar.grid(row=0, column=1, sticky='nsew')
    right_canvas['yscrollcommand'] = right_scrollbar.set
    
    right_canvas.columnconfigure(0, weight=1)
    right_canvas.rowconfigure(0, weight=1)
    
    right_final_window = tk.Frame(right_canvas, bg='green')
    right_canvas.create_window((0, 0), window=right_final_window, anchor='nw', tags='expand')
    right_final_window.columnconfigure(0, weight=1)
    
    for i in range(1, 51):
        label = tk.Label(right_final_window, text=f'Manish Pushpam ({i})')
        label.grid(row=i-1, column=0, sticky='nsew', pady=(0, 2))
    
    right_canvas.bind_all('<Configure>', lambda event: right_canvas.itemconfigure('expand', width=event.width))
    right_final_window.update_idletasks()
    right_canvas.config(scrollregion=right_canvas.bbox('all'))
    
    right_canvas.bind("<Enter>", lambda event: final_scroll(event, right_canvas, lambda event: scroll(event, right_canvas)))
    right_canvas.bind("<Leave>", lambda event: stop_scroll(event, right_canvas))
    root.mainloop()
    

    【讨论】:

    • 非常感谢您非常有趣的回答。但是您知道如何将框架置于其区域的中心吗?还有如何让鼠标滚轮上下移动的可能性?
    • @Mo0nKizz ,现在你可以再检查一下,我已经添加了使用鼠标滚轮滚动
    • 你是救生员!!!十分感谢 ?但是你怎么知道如何解决我所有的问题? :)
    • 过去我也面临同样的问题,我阅读了大量文档来解决我的问题。
    • 你知道如何让标签在框架中居中吗?
    【解决方案3】:

    这个修正解决了这个问题。玩它。还学习如何使用 ttk 美化你的 GUI

    
    
    from tkinter import *
    
    root = Tk()
    
    root.columnconfigure(0, weight=1)
    root.columnconfigure(2, weight=1)
    
    canvasL = Canvas(root, bg='blue')
    canvasL.grid(row=0, column=0, sticky="news")
    
    canvasR = Canvas(root, bg='blue')
    canvasR.grid(row=0, column=2, sticky="news")
    
    frameL = Frame(canvasL, bg='red', width=1000)
    frameL.grid(row=0, column=0, sticky="news")
    
    frameR = Frame(canvasR, bg='red')
    frameR.grid(row=0, column=0, sticky="news")
    
    frameL.grid_propagate(False)
    frameR.grid_propagate(False)
    
    S1 = Scrollbar(frameL, orient="vertical", command=canvasL.yview)
    S1.grid(row=0, column=1, sticky="news")
    
    S2 = Scrollbar(frameR, orient="vertical", command=canvasR.yview)
    S2.grid(row=0, column=3, sticky="news")
    
    canvasL.configure(yscrollcommand=S1.set)
    canvasL.configure(scrollregion=canvasL.bbox("all"))
    
    canvasR.configure(yscrollcommand=S2.set)
    canvasR.configure(scrollregion=canvasR.bbox("all"))
    
    canvasL.create_window((0, 0), anchor='nw', window=frameL)
    canvasR.create_window((0, 0), anchor='nw', window=frameR)
    
    for i in range(0, 40):
    #use the cavasL and canvasR directly, they are at the closer to #the root
        labelName = Label(canvasL, text="Name : " + str(i), bg='#F5F5F5')
        labelName.grid(row=i, column=0)
        labelName = Label(canvasR, text="Name : " + str(i), bg='#F5F5F5')
        labelName.grid(row=i, column=2)
    
    root.mainloop()
    

    【讨论】:

    • 不,我认为您的回答并不能解决问题。我没有你更正的滚动条。
    • 哎呀,让我看看
    猜你喜欢
    • 1970-01-01
    • 2022-01-09
    • 2017-09-29
    • 2017-07-03
    • 2020-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-06
    相关资源
    最近更新 更多