python tkinter运行时grid函数直接使用不执行但是作为按钮的命令正常执行

在编写GUI的过程中,需要将一个按钮的命令单独拎出来执行,其他都正常执行但是grid却没有任何效果,这部分代码如下,重点在最后一段代码

from tkinter import *
from draggableWindow import move_window as m_w
from windowSet import windowSet
import numpy as np
import os
import time


def close_window(event): # 设置关闭窗口的程序
    from tkinter import messagebox

    if messagebox.askokcancel('退出','请确认是否退出程序'):
        root.destroy()


def _on_mousewheel(event):  # 鼠标滚轮
        canvas_main.yview_scroll(int(-1 * (event.delta / 120)), "units")


root = Tk()


sw = root.winfo_screenwidth()
sh = root.winfo_screenheight()
ww = 1280
wh = 720
x = int((sw - ww) / 2)
y = int((sh - wh) / 2)
root.title("燃烧炉监测窗口")
root.geometry(f'{ww}x{wh}+{x}+{y}')
#root.overrideredirect(True)
m_w(root)
root.bind('',close_window) # 将close_window与Esc键绑定


savedSettings = {}

if os.path.isfile('Settings.npy'):
    savedSettings = np.load('Settings.npy',allow_pickle = True).item()


canvas_main = Canvas(root,width = ww - 21,height = wh - 33,highlightthickness = 0,bg = 'pink')
scrollbar_main = Scrollbar(root,orient = "vertical",command = canvas_main.yview)
f_main = Frame(canvas_main)
f_main.bind("",lambda e: canvas_main.config(scrollregion = canvas_main.bbox('all')))
canvas_main.create_window((0, 0),window = f_main,anchor = "nw")
canvas_main.config(yscrollcommand = scrollbar_main.set)
canvas_main.grid(row = 0,column = 0,sticky = NW)
scrollbar_main.grid(row = 0,column = 1,sticky = NS)
canvas_main.bind_all("", _on_mousewheel)  # 绑定鼠标滚轮


btSet = Button(root,text = '设置',command = lambda: windowSet(root,savedSettings,f_main),font = ('微软雅黑',10))
btSet.place(relx=1,rely=1,anchor = SE)


if savedSettings != {}:
    widgt_c = 0

    for i in range(4):

        if savedSettings[f"CheckVar{1 + i}"] == 1:
            widgt_c += 1

        if savedSettings[f"CheckVar{1 + i}"] == 1:
            widgt_c += savedSettings['customizeWidgt_n']

    for i in range(widgt_c):
        print(1)
        globals()[f"f_{1 + i}"] = Frame(f_main,width = (root.winfo_width() - 21) / 3,height = (root.winfo_height() - 33) / 3,bg = 'blue')
        globals()[f"f_{1 + i}"].grid(row = int(i / 3),column = i % 3,sticky = NW)
        globals()[f"f_{1 + i}"].grid_propagate(False)


root.mainloop()

运行结果如下

img

img

img

通过按钮执行的效果如下

img


第一张图中的4个1证明这段代码正确的被运行了但是f_1,2,3,4却没有在窗口中
这是出现了什么问题呢?也没有报错

参考GPT和自己的思路,在代码中,globals()[f"f_{1 + i}"] 会动态创建变量名为 f_{1 + i} 的变量,但是在最后的代码中使用 f_{1 + i} 来引用这些变量,这是不正确的,应该使用 globals()[f"f_{1 + i}"] 来引用这些变量。

修改后的代码如下:

if savedSettings != {}:
    widgt_c = 0

    for i in range(4):

        if savedSettings[f"CheckVar{1 + i}"] == 1:
            widgt_c += 1

        if savedSettings[f"CheckVar{1 + i}"] == 1:
            widgt_c += savedSettings['customizeWidgt_n']

    for i in range(widgt_c):
        print(1)
        frame = Frame(f_main, width=(root.winfo_width() - 21) / 3, height=(root.winfo_height() - 33) / 3, bg='blue')
        globals()[f"f_{1 + i}"] = frame
        frame.grid(row=int(i / 3), column=i % 3, sticky=NW)
        frame.grid_propagate(False)

在这个修改后的代码中,我们在创建每个 frame 的时候,使用一个变量名为 frame 的变量引用它,然后使用 globals() 函数来动态创建变量名为 f_{1 + i} 的变量,并将 frame 赋值给这个变量。然后,我们在 grid 函数中使用 frame 来引用这些变量。

该回答引用ChatGPT

根据你提供的代码和运行结果,可以看出按钮的命令是通过lambda表达式调用windowSet函数,并将f_main作为参数传递给该函数。在windowSet函数内部,它可能修改了f_main中的控件,但你的代码并没有更新Canvas的scrollregion属性,这导致Canvas不知道需要滚动的区域的大小。

要解决这个问题,可以在windowSet函数中添加代码,以便在更新f_main后更新Canvas的scrollregion属性,如下所示:

def windowSet(root,savedSettings,f_main):
    # do something to modify f_main
    f_main.update_idletasks()  # update f_main to get its new size
    root.update_idletasks()  # update root to get its new size
    canvas_main.config(scrollregion=canvas_main.bbox("all"))


在这里,update_idletasks()方法被调用来确保所有窗口控件都已经更新,canvas_main.bbox("all")返回一个元组,该元组表示Canvas中所有子控件的边界框(bounding box),并将其用作scrollregion属性的值。

这样,当windowSet函数执行完毕后,Canvas就能够正确地显示f_main中的所有控件,并且滚动条也可以按预期工作。

先不通过按钮,把这几个frame单独拿出来看看能不能正常显示,显示的样子如何?
另外检查一下 width = (root.winfo_width() - 21) / 3,height = (root.winfo_height() - 33) / 3 这两个数的位置。

借鉴下
https://www.yingsoo.com/news/devops/66879.html