【问题标题】:Resizing the Canvas equal to the frame size in tkinter python在 tkinter python 中将画布大小调整为等于帧大小
【发布时间】:2020-11-22 05:51:35
【问题描述】:

我有两个与此附加代码相关的问题。这段代码是我项目的一部分,我必须管理 50 名(或更多)学生的出勤率。

  1. 当您运行这段代码时,您会看到标签框架内有一个额外的空白区域(可能是画布),即 Attendance_Frame。我想要的是不应该有额外的空白,滚动条应该在标签结束的地方,而不是在最右边。 我已经搜索了我的问题的答案并看到了类似的案例。但是在那里,这个人希望框架扩展到画布大小。链接 (Tkinter: How to get frame in canvas window to expand to the size of the canvas?)。 但就我而言,我希望画布大小等于框架大小(尽管框架位于画布内)

  2. 我想要的另一件事是所有复选框最初都应该被“选中”(显示当前状态),当我取消选中随机复选框(以标记不存在),然后单击“提交”按钮(尚未在窗口底部创建),我应该得到一个列表,其中“输入的日期”作为第一个元素,卷号即 2018-MC-XX 作为其他元素。例如:['01/08/2020'、'2018-MC-7'、'2018-MC-11'、'2018-MC-23'、'2018-MC-44']。 实际上我的计划是当我得到一个列表时,我会很容易地将它写入一个文本文件。

     from tkinter import *
     from tkcalendar import DateEntry
    
     root = Tk()
     root.geometry('920x600+270+50')
     root.minsize(920,600)
    
     Attendance_frame = Frame(root)    ### Consider it a Main Frame
     Attendance_frame.pack()
    
     attendaceBox = LabelFrame(Attendance_frame, text = 'Take Attendance', bd = 4, relief = GROOVE, labelanchor = 'n',font = 'Arial 10 bold', fg = 'navy blue', width = 850, height = 525)     # A Label Frame inside the main frame
    
     attendaceBox.pack_propagate(0)
     attendaceBox.pack(pady = 15)
    
     dateFrame = Frame(attendaceBox)    # A small frame to accommodate date entry label & entry box
     dateFrame.pack(anchor = 'w')
    
     font = 'TkDefaultFont 10 bold'
     date_label = Label(dateFrame, text = 'Enter Date : ', font = font).grid(row = 0, column =  0, sticky = 'w', padx = 10, pady = 10)
    
     date_entry = DateEntry(dateFrame, date_pattern = 'dd/mm/yyyy', showweeknumbers = FALSE, showothermonthdays = FALSE)
     date_entry.grid(row = 0, column = 1, sticky = 'w')
    
     noteLabel = Label(attendaceBox, text = 'Note: Uncheck the boxes for absentees').pack(anchor = 'w', padx = 10, pady = 5)
    
     canvas = Canvas(attendaceBox, borderwidth=0, background="#ffffff")
     checkFrame = Frame(canvas, width = 100, height = 50)
     vsb = Scrollbar(canvas, orient="vertical", command=canvas.yview)
     canvas.configure(yscrollcommand=vsb.set)
    
     vsb.pack(side="right", fill="y")
     canvas.pack(side="left", fill="both", expand=True)
     canvas.pack_propagate(0)
     canvas.create_window((4,4), window=checkFrame, anchor="nw")
    
     def onFrameConfigure(canvas):
         '''Reset the scroll region to encompass the inner frame'''
         canvas.configure(scrollregion=canvas.bbox("all"))
    
     checkFrame.bind("<Configure>", lambda event, canvas=canvas: onFrameConfigure(canvas))
    
     for i in range(0,51):     # A loop to create Labels of students roll numbers & names
         c = Checkbutton(checkFrame, text = f"{'2018-MC-'+str(i+1)}       Student {i+1}")
         c.grid(row = i, column = 0, padx = 10, sticky = 'w')
    
    
     mainloop()
    

【问题讨论】:

  • 您可以通过临时使用独特的颜色来确定额外的空白是什么。给你的画布一种颜色,另一种颜色checkFrame,另一种颜色attendaceBox。此外,StackOverflow 指南建议一个问题应该只问一件事。
  • 如果您只是想创建一个可滚动的复选框垂直列表,有比将它们放在画布内的框架中更简单的技术。您是否对这些想法感兴趣,或者您是否特别想要解决这个问题?
  • 您可以在代码canvas.create_window((4, 4), window=checkFrame, anchor="nw", tags='expand')canvas.bind('&lt;Configure&gt;', lambda event: canvas.itemconfigure('expand', width=event.width)) 中尝试这一行
  • @Manish Pushpam,这些行删除了空白,但滚动条仍然位于窗口的最末端。我希望它位于标签列表之后,而不是整个窗口。希望你能理解。
  • @Bryan Oakley,先生,多余的空间属于 Canvas 小部件。

标签: python tkinter canvas


【解决方案1】:

如果您要创建垂直的项目列表,则无需在画布内使用框架。内部框架增加了一些不必要的复杂性。相反,使用create_window 在画布上直接创建复选按钮。

您还需要配置scrollregion 属性,以便滚动条知道要滚动多少虚拟画布。

最后,要选择它们,您应该为每个检查按钮分配一个变量,并确保该值是正确的值。默认情况下,检查按钮使用值 0 和 1,因此将变量设置为 1 将使其被选中。

vars = []
for i in range(0,51):
    var = IntVar(value=1)
    vars.append(var)
    x0, y0, x1, y1 = canvas.bbox("all") or (0,0,0,0)
    c = Checkbutton(canvas, text = f"{'2018-MC-'+str(i+1)}       Student {i+1}", variable=var)
    canvas.create_window(2, y1+4, anchor="nw", window=c)
canvas.configure(scrollregion=canvas.bbox("all"))

【讨论】:

    【解决方案2】:

    您所有问题的答案都在这里:

    你应该试试这个。


    import tkinter as tk
    from tkcalendar import DateEntry
    
    root = tk.Tk()
    root.geometry('920x600+270+50')
    root.minsize(960, 600)
    
    root.columnconfigure(0, weight=1)
    root.rowconfigure(0, weight=1)
    Attendance_frame = tk.Frame(root)
    Attendance_frame.grid(row=0, column=0, sticky='nsew')
    
    attendaceBox = tk.LabelFrame(Attendance_frame,
                                 text='Take Attendance',
                                 bd=4,
                                 relief='groove',
                                 labelanchor='n',
                                 font='Arial 10 bold',
                                 fg='navy blue',
                                 width=850,
                                 height=525)
    attendaceBox.grid(row=0, column=0, sticky='nsew', padx=15)
    
    Attendance_frame.columnconfigure(0, weight=1)
    Attendance_frame.rowconfigure(0,weight=1)
    
    dateFrame = tk.Frame(attendaceBox)  # A small frame to accommodate date entry label & entry box
    dateFrame.grid(row=0, column=0, sticky='nsew')
    
    font = 'TkDefaultFont 10 bold'
    date_label = tk.Label(dateFrame, text='Enter Date : ', font=font)
    date_label.grid(row=0, column=0, sticky='w', padx=10, pady=10)
    
    date_entry = DateEntry(dateFrame, date_pattern='dd/mm/yyyy', showweeknumbers=False, showothermonthdays=False)
    date_entry.grid(row=0, column=1, sticky='w')
    
    noteLabel = tk.Label(attendaceBox, text='Note: Uncheck the boxes for absentees', anchor='w')
    noteLabel.grid(row=1, column=0, sticky='nsew')
    
    attendaceBox.rowconfigure(2, weight=1)
    canvas = tk.Canvas(attendaceBox, width=200, borderwidth=0, background="#ffffff")
    # You can set width of canvas according to your need
    canvas.grid(row=2, column=0, sticky='nsew')
    canvas.columnconfigure(0, weight=1)
    canvas.rowconfigure(0, weight=1)
    vsb = tk.Scrollbar(attendaceBox, orient="vertical", command=canvas.yview)
    vsb.grid(row=2, column=1, sticky='nsew')
    canvas.configure(yscrollcommand=vsb.set)
    
    checkFrame = tk.Frame(canvas, bg='green')
    canvas.create_window((0, 0), window=checkFrame, anchor="nw", tags='expand')
    checkFrame.columnconfigure(0, weight=1)
    
    
    
    for i in range(0, 51):  # A loop to create Labels of students roll numbers & names
        c = tk.Checkbutton(checkFrame, anchor='w', text=f"{'2018-MC-' + str(i + 1)}       Student {i + 1}")
        c.grid(row=i, column=0, sticky='nsew')
        c.select()
    canvas.bind('<Configure>', lambda event: canvas.itemconfigure('expand', width=event.width))
    checkFrame.update_idletasks()
    canvas.config(scrollregion=canvas.bbox('all'))
    
    
    root.mainloop()
    

    获取选定的值

    vars = []
    for i in range(0, 51):  # A loop to create Labels of students roll numbers & names
        var = tk.IntVar()
        c = tk.Checkbutton(checkFrame,
                           variable=var,
                           anchor='w', text=f"{'2018-MC-' + str(i + 1)}       Student {i + 1}")
        c.grid(row=i, column=0, sticky='nsew')
        c.select()
        vars.append(var)
    
    
    def state():
        print(list(map((lambda var: var.get()), vars)))
    

    【讨论】:

    • 以后如何获取checkbuttons的check状态?
    • @acw1668,您可以查看我的答案,现在您的问题的答案已编辑。
    • 如果你解释你做了什么,这个答案会更好。否则,我们必须逐行逐字符地将您的代码与原始代码进行比较,以查看您所做的更改。
    猜你喜欢
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    • 2016-06-29
    • 1970-01-01
    • 2014-05-15
    • 1970-01-01
    • 2011-11-15
    • 2021-04-28
    相关资源
    最近更新 更多