如何不使用global关键字实现tkinter应用内的变量更新
问题原因
你的判断是正确的,核心问题是外层的gameDate变量从未被更新,每次按钮触发lambda时,传入的都是初始的1985年9月1日的日期值,函数返回的新日期没有被存储到外层变量,所以每次点击都是在初始值基础上加1个月,只会显示1985年10月。
不使用global的解决方案
下面提供两种常用的实现方案:
方案1:用可变容器存储日期(最小改动适配原有代码)
列表、字典属于可变对象,修改内部元素不需要重新绑定外层变量,只要把日期放到列表中即可实现状态同步,修改后的完整代码如下:
import datetime from dateutil.relativedelta import relativedelta from tkinter import * # 用列表包裹日期作为可变容器 gameDate = [datetime.datetime(1985, 9, 1)] def nextMonth(date_container, worldDateLabel): # 直接修改容器内的元素 date_container[0] = date_container[0] + relativedelta(months=1) worldDateLabel.config(text=date_container[0].strftime("%B %Y")) window = Tk() worldDateLabel = Label(window, text=gameDate[0].strftime("%B %Y")) worldDateLabel.grid(row=0, column=0) next_btn = Button(window, text="Next Month", command=lambda:nextMonth(gameDate, worldDateLabel)) next_btn.grid(row=1, column=0) window.mainloop()
方案2:用类封装逻辑(更适合项目扩展的规范写法)
把整个界面逻辑封装为类,日期作为类的实例属性存储,完全不需要依赖全局变量,后续新增功能的可维护性更高:
import datetime from dateutil.relativedelta import relativedelta from tkinter import * class DateGame: def __init__(self, root): self.root = root self.gameDate = datetime.datetime(1985, 9, 1) self.worldDateLabel = Label(root, text=self.gameDate.strftime("%B %Y")) self.worldDateLabel.grid(row=0, column=0) self.next_btn = Button(root, text="Next Month", command=self.nextMonth) self.next_btn.grid(row=1, column=0) def nextMonth(self): self.gameDate = self.gameDate + relativedelta(months=1) self.worldDateLabel.config(text=self.gameDate.strftime("%B %Y")) if __name__ == "__main__": window = Tk() app = DateGame(window) window.mainloop()
内容的提问来源于stack exchange,提问作者Gobhniu
相关产品推荐
相关产品推荐

