I am trying to make a program that adds one month to a date variable every time the user presses a button.
Here's my code:
import datetime
from dateutil.relativedelta import relativedelta
from tkinter import *
gameDate = datetime.datetime(1985, 9, 1)
def nextMonth(gameDate, worldDateLabel):
gameDate = gameDate relativedelta(months=1)
worldDateLabel.config(text=gameDate.strftime("%B %Y"))
return gameDate
window = Tk()
worldDateLabel = Label(window, text=gameDate.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()
The date updates the first time I click on the button but then it stays to October and doesn't move to the next month.
I think it's because the program updates only the local variable inside the function instead of the main gameDate
one. I tried to fix that with the return at the end but that doesn't help.
I am not sure what I am doing wrong…
P.S.: I am trying not to use global
.
CodePudding user response:
You need global in this case. The general rule to avoid globals has many exceptions. The problem with global variables is that it tends to couple different functions in a non-obvious way that may be better off being independent of each other. Think easier programming and fewer bugs.
The simpler the script, the less this is a concern. In your case, you have a program with a single main event loop, having a few extra global variables with that is okay. But as your code grows and you find different uses for that nextMonth
function, that's when it gets to be a problem.
One way to solve the problem is with a class. A class instance method remembers its instance, so you could define a class that does useful game date stuff. The class instance itself is still global, but then so is the Tk window. But you have now encapsulated the functionality and can use that class elsewhere if you want.
import datetime
from dateutil.relativedelta import relativedelta
from tkinter import *
class GameDate:
def __init__(self):
self.gameDate = datetime.datetime(1985, 9, 1)
def nextMonth(self, worldDateLabel):
self.gameDate = self.gameDate relativedelta(months=1)
worldDateLabel.config(text=self.gameDate.strftime("%B %Y"))
window = Tk()
date = GameDate()
worldDateLabel = Label(window, text=gameDate.strftime("%B %Y"))
worldDateLabel.grid(row=0, column=0)
next_btn = Button(window, text="Next Month", command=lambda:date.nextMonth(worldDateLabel))
next_btn.grid(row=1, column=0)
window.mainloop()