在编写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()
运行结果如下
通过按钮执行的效果如下
参考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 这两个数的位置。